summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xautogen.sh2
-rw-r--r--configure.ac10
-rw-r--r--data/Makefile.am2
-rw-r--r--data/keyboards/Makefile.am58
-rw-r--r--data/keyboards/hangul-combination-default.xml40
-rw-r--r--data/keyboards/hangul-combination-full.xml356
-rw-r--r--data/keyboards/hangul-keyboard-2.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-2y.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-32.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-39.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-3f.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-3s.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-3y.xml.template105
-rw-r--r--data/keyboards/hangul-keyboard-ahn.xml.template186
-rw-r--r--data/keyboards/hangul-keyboard-ro.xml.template151
-rw-r--r--hangul/Makefile.am11
-rw-r--r--hangul/hangul.h29
-rw-r--r--hangul/hangulinputcontext.c375
-rw-r--r--hangul/hangulinternals.h31
-rw-r--r--hangul/hangulkeyboard.c950
-rw-r--r--po/POTFILES.in2
-rw-r--r--test/hangul.c4
-rw-r--r--test/test.c12
-rw-r--r--tools/hangul.c12
25 files changed, 2603 insertions, 364 deletions
diff --git a/.gitignore b/.gitignore
index 7cb2394..7816a9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ config.sub
configure
data/hanja/Makefile
data/hanja/Makefile.in
+data/keyboards/hangul-keyboard-*.xml
depcomp
doc/Doxyfile
doc/hangulkeyboards.dox
diff --git a/autogen.sh b/autogen.sh
index 635edf6..97617b2 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -8,7 +8,7 @@ if test -z "$libtoolize"; then
libtoolize=libtoolize
fi
-autopoint --force
+intltoolize --copy --force
$libtoolize --automake --copy --force
aclocal $ACLOCAL_AMFLAGS
autoheader
diff --git a/configure.ac b/configure.ac
index cde5bad..95e89c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,6 +16,8 @@ AC_SUBST(LIBHANGUL_CURRENT)
AC_SUBST(LIBHANGUL_REVISION)
AC_SUBST(LIBHANGUL_AGE)
+IT_PROG_INTLTOOL
+
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
@@ -48,12 +50,13 @@ AC_CHECK_FUNCS([nl_langinfo])
GETTEXT_PACKAGE="$PACKAGE"
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", gettext package name)
-AM_GNU_GETTEXT([external])
-AM_GNU_GETTEXT_VERSION(0.18)
AM_ICONV
-# Checks for unit test framework
+# Checks for expat
PKG_PROG_PKG_CONFIG
+PKG_CHECK_MODULES(EXPAT, [expat])
+
+# Checks for unit test framework
if test -n "$PKG_CONFIG"; then
PKG_CHECK_EXISTS(check, [ PKG_CHECK_MODULES([CHECK], [check]) ])
fi
@@ -62,6 +65,7 @@ AC_CONFIG_FILES([
Makefile
data/Makefile
data/hanja/Makefile
+data/keyboards/Makefile
doc/Doxyfile
hangul/Makefile
libhangul.pc
diff --git a/data/Makefile.am b/data/Makefile.am
index b60de42..6f8340e 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1 +1 @@
-SUBDIRS = hanja
+SUBDIRS = hanja keyboards
diff --git a/data/keyboards/Makefile.am b/data/keyboards/Makefile.am
new file mode 100644
index 0000000..12b5459
--- /dev/null
+++ b/data/keyboards/Makefile.am
@@ -0,0 +1,58 @@
+
+keyboardsdir = $(pkgdatadir)/keyboards
+keyboards_DATA = \
+ hangul-keyboard-2.xml \
+ hangul-keyboard-2y.xml \
+ hangul-keyboard-39.xml \
+ hangul-keyboard-3f.xml \
+ hangul-keyboard-32.xml \
+ hangul-keyboard-3s.xml \
+ hangul-keyboard-3y.xml \
+ hangul-keyboard-ro.xml \
+ hangul-keyboard-ahn.xml \
+ hangul-combination-default.xml \
+ hangul-combination-full.xml \
+ $(NULL)
+
+EXTRA_DIST = \
+ hangul-keyboard-2.xml.template \
+ hangul-keyboard-2y.xml.template \
+ hangul-keyboard-39.xml.template \
+ hangul-keyboard-3f.xml.template \
+ hangul-keyboard-32.xml.template \
+ hangul-keyboard-3s.xml.template \
+ hangul-keyboard-3y.xml.template \
+ hangul-keyboard-ro.xml.template \
+ hangul-keyboard-ahn.xml.template \
+ hangul-combination-default.xml \
+ hangul-combination-full.xml \
+ $(NULL)
+
+# intltool로 xml 파일을 번역하면 주석이 모두 사라지고 attr의 순서도
+# 재정렬된다. 이를 방지하고자 name 부분만 별도의 name.xml로 만들어
+# 번역한후 template과 name.xml을 병합하여 키보드 xml 파일을 생성한다.
+hangul-keyboard-%.xml: hangul-keyboard-%.name.xml hangul-keyboard-%.xml.template
+ sed -i -e '1 D' -e 's/^<name/ <name/' $<
+ sed \
+ -e '/<_name>/r $<' \
+ -e '/<_name>/a\ ' \
+ -e '/<_name>/D' \
+ $(srcdir)/$@.template > $@
+
+hangul-keyboard-%.name.xml.in: hangul-keyboard-%.xml.template
+ grep "xml version=" $< > $@
+ grep "<_name>" $< >> $@
+
+CLEANFILES = \
+ hangul-keyboard-2.xml \
+ hangul-keyboard-2y.xml \
+ hangul-keyboard-39.xml \
+ hangul-keyboard-3f.xml \
+ hangul-keyboard-32.xml \
+ hangul-keyboard-3s.xml \
+ hangul-keyboard-3y.xml \
+ hangul-keyboard-ro.xml \
+ hangul-keyboard-ahn.xml \
+ $(NULL)
+
+@INTLTOOL_XML_RULE@
diff --git a/data/keyboards/hangul-combination-default.xml b/data/keyboards/hangul-combination-default.xml
new file mode 100644
index 0000000..53eb30d
--- /dev/null
+++ b/data/keyboards/hangul-combination-default.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<combination id="0">
+ <item first="0x1100" second="0x1100" result="0x1101"/> <!-- ᄀ + ᄀ → ᄁ -->
+ <item first="0x1100" second="0x1109" result="0x11aa"/> <!-- ᄀ + ᄉ → ᆪ -->
+ <item first="0x1102" second="0x110c" result="0x11ac"/> <!-- ᄂ + ᄌ → ᆬ -->
+ <item first="0x1102" second="0x1112" result="0x11ad"/> <!-- ᄂ + ᄒ → ᆭ -->
+ <item first="0x1103" second="0x1103" result="0x1104"/> <!-- ᄃ + ᄃ → ᄄ -->
+ <item first="0x1105" second="0x1100" result="0x11b0"/> <!-- ᄅ + ᄀ → ᆰ -->
+ <item first="0x1105" second="0x1106" result="0x11b1"/> <!-- ᄅ + ᄆ → ᆱ -->
+ <item first="0x1105" second="0x1107" result="0x11b2"/> <!-- ᄅ + ᄇ → ᆲ -->
+ <item first="0x1105" second="0x1109" result="0x11b3"/> <!-- ᄅ + ᄉ → ᆳ -->
+ <item first="0x1105" second="0x1110" result="0x11b4"/> <!-- ᄅ + ᄐ → ᆴ -->
+ <item first="0x1105" second="0x1111" result="0x11b5"/> <!-- ᄅ + ᄑ → ᆵ -->
+ <item first="0x1105" second="0x1112" result="0x11b6"/> <!-- ᄅ + ᄒ → ᆶ -->
+ <item first="0x1107" second="0x1107" result="0x1108"/> <!-- ᄇ + ᄇ → ᄈ -->
+ <item first="0x1107" second="0x1109" result="0x11b9"/> <!-- ᄇ + ᄉ → ᆹ -->
+ <item first="0x1109" second="0x1109" result="0x110a"/> <!-- ᄉ + ᄉ → ᄊ -->
+ <item first="0x110c" second="0x110c" result="0x110d"/> <!-- ᄌ + ᄌ → ᄍ -->
+ <item first="0x1169" second="0x1161" result="0x116a"/> <!-- ᅩ + ᅡ → ᅪ -->
+ <item first="0x1169" second="0x1162" result="0x116b"/> <!-- ᅩ + ᅢ → ᅫ -->
+ <item first="0x1169" second="0x1175" result="0x116c"/> <!-- ᅩ + ᅵ → ᅬ -->
+ <item first="0x116e" second="0x1165" result="0x116f"/> <!-- ᅮ + ᅥ → ᅯ -->
+ <item first="0x116e" second="0x1166" result="0x1170"/> <!-- ᅮ + ᅦ → ᅰ -->
+ <item first="0x116e" second="0x1175" result="0x1171"/> <!-- ᅮ + ᅵ → ᅱ -->
+ <item first="0x1173" second="0x1175" result="0x1174"/> <!-- ᅳ + ᅵ → ᅴ -->
+ <item first="0x11a8" second="0x11a8" result="0x11a9"/> <!-- ᆨ + ᆨ → ᆩ -->
+ <item first="0x11a8" second="0x11ba" result="0x11aa"/> <!-- ᆨ + ᆺ → ᆪ -->
+ <item first="0x11ab" second="0x11bd" result="0x11ac"/> <!-- ᆫ + ᆽ → ᆬ -->
+ <item first="0x11ab" second="0x11c2" result="0x11ad"/> <!-- ᆫ + ᇂ → ᆭ -->
+ <item first="0x11af" second="0x11a8" result="0x11b0"/> <!-- ᆯ + ᆨ → ᆰ -->
+ <item first="0x11af" second="0x11b7" result="0x11b1"/> <!-- ᆯ + ᆷ → ᆱ -->
+ <item first="0x11af" second="0x11b8" result="0x11b2"/> <!-- ᆯ + ᆸ → ᆲ -->
+ <item first="0x11af" second="0x11ba" result="0x11b3"/> <!-- ᆯ + ᆺ → ᆳ -->
+ <item first="0x11af" second="0x11c0" result="0x11b4"/> <!-- ᆯ + ᇀ → ᆴ -->
+ <item first="0x11af" second="0x11c1" result="0x11b5"/> <!-- ᆯ + ᇁ → ᆵ -->
+ <item first="0x11af" second="0x11c2" result="0x11b6"/> <!-- ᆯ + ᇂ → ᆶ -->
+ <item first="0x11b8" second="0x11ba" result="0x11b9"/> <!-- ᆸ + ᆺ → ᆹ -->
+ <item first="0x11ba" second="0x11ba" result="0x11bb"/> <!-- ᆺ + ᆺ → ᆻ -->
+</combination>
diff --git a/data/keyboards/hangul-combination-full.xml b/data/keyboards/hangul-combination-full.xml
new file mode 100644
index 0000000..318d7ec
--- /dev/null
+++ b/data/keyboards/hangul-combination-full.xml
@@ -0,0 +1,356 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<combination id="0">
+ <item first="0x1100" second="0x1100" result="0x1101"/> <!-- ᄀ + ᄀ → ᄁ -->
+ <item first="0x1100" second="0x1103" result="0x115a"/> <!-- ᄀ + ᄃ → ᅚ -->
+ <item first="0x1102" second="0x1100" result="0x1113"/> <!-- ᄂ + ᄀ → ᄓ -->
+ <item first="0x1102" second="0x1102" result="0x1114"/> <!-- ᄂ + ᄂ → ᄔ -->
+ <item first="0x1102" second="0x1103" result="0x1115"/> <!-- ᄂ + ᄃ → ᄕ -->
+ <item first="0x1102" second="0x1107" result="0x1116"/> <!-- ᄂ + ᄇ → ᄖ -->
+ <item first="0x1102" second="0x1109" result="0x115b"/> <!-- ᄂ + ᄉ → ᅛ -->
+ <item first="0x1102" second="0x110c" result="0x115c"/> <!-- ᄂ + ᄌ → ᅜ -->
+ <item first="0x1102" second="0x1112" result="0x115d"/> <!-- ᄂ + ᄒ → ᅝ -->
+ <item first="0x1103" second="0x1100" result="0x1117"/> <!-- ᄃ + ᄀ → ᄗ -->
+ <item first="0x1103" second="0x1103" result="0x1104"/> <!-- ᄃ + ᄃ → ᄄ -->
+ <item first="0x1103" second="0x1105" result="0x115e"/> <!-- ᄃ + ᄅ → ᅞ -->
+ <item first="0x1103" second="0x1106" result="0xa960"/> <!-- ᄃ + ᄆ → ꥠ -->
+ <item first="0x1103" second="0x1107" result="0xa961"/> <!-- ᄃ + ᄇ → ꥡ -->
+ <item first="0x1103" second="0x1109" result="0xa962"/> <!-- ᄃ + ᄉ → ꥢ -->
+ <item first="0x1103" second="0x110c" result="0xa963"/> <!-- ᄃ + ᄌ → ꥣ -->
+ <item first="0x1105" second="0x1100" result="0xa964"/> <!-- ᄅ + ᄀ → ꥤ -->
+ <item first="0x1105" second="0x1101" result="0xa965"/> <!-- ᄅ + ᄁ → ꥥ -->
+ <item first="0x1105" second="0x1102" result="0x1118"/> <!-- ᄅ + ᄂ → ᄘ -->
+ <item first="0x1105" second="0x1103" result="0xa966"/> <!-- ᄅ + ᄃ → ꥦ -->
+ <item first="0x1105" second="0x1104" result="0xa967"/> <!-- ᄅ + ᄄ → ꥧ -->
+ <item first="0x1105" second="0x1105" result="0x1119"/> <!-- ᄅ + ᄅ → ᄙ -->
+ <item first="0x1105" second="0x1106" result="0xa968"/> <!-- ᄅ + ᄆ → ꥨ -->
+ <item first="0x1105" second="0x1107" result="0xa969"/> <!-- ᄅ + ᄇ → ꥩ -->
+ <item first="0x1105" second="0x1108" result="0xa96a"/> <!-- ᄅ + ᄈ → ꥪ -->
+ <item first="0x1105" second="0x1109" result="0xa96c"/> <!-- ᄅ + ᄉ → ꥬ -->
+ <item first="0x1105" second="0x110b" result="0x111b"/> <!-- ᄅ + ᄋ → ᄛ -->
+ <item first="0x1105" second="0x110c" result="0xa96d"/> <!-- ᄅ + ᄌ → ꥭ -->
+ <item first="0x1105" second="0x110f" result="0xa96e"/> <!-- ᄅ + ᄏ → ꥮ -->
+ <item first="0x1105" second="0x1112" result="0x111a"/> <!-- ᄅ + ᄒ → ᄚ -->
+ <item first="0x1105" second="0x112b" result="0xa96b"/> <!-- ᄅ + ᄫ → ꥫ -->
+ <item first="0x1106" second="0x1100" result="0xa96f"/> <!-- ᄆ + ᄀ → ꥯ -->
+ <item first="0x1106" second="0x1103" result="0xa970"/> <!-- ᄆ + ᄃ → ꥰ -->
+ <item first="0x1106" second="0x1107" result="0x111c"/> <!-- ᄆ + ᄇ → ᄜ -->
+ <item first="0x1106" second="0x1109" result="0xa971"/> <!-- ᄆ + ᄉ → ꥱ -->
+ <item first="0x1106" second="0x110b" result="0x111d"/> <!-- ᄆ + ᄋ → ᄝ -->
+ <item first="0x1107" second="0x1100" result="0x111e"/> <!-- ᄇ + ᄀ → ᄞ -->
+ <item first="0x1107" second="0x1102" result="0x111f"/> <!-- ᄇ + ᄂ → ᄟ -->
+ <item first="0x1107" second="0x1103" result="0x1120"/> <!-- ᄇ + ᄃ → ᄠ -->
+ <item first="0x1107" second="0x1107" result="0x1108"/> <!-- ᄇ + ᄇ → ᄈ -->
+ <item first="0x1107" second="0x1109" result="0x1121"/> <!-- ᄇ + ᄉ → ᄡ -->
+ <item first="0x1107" second="0x110a" result="0x1125"/> <!-- ᄇ + ᄊ → ᄥ -->
+ <item first="0x1107" second="0x110b" result="0x112b"/> <!-- ᄇ + ᄋ → ᄫ -->
+ <item first="0x1107" second="0x110c" result="0x1127"/> <!-- ᄇ + ᄌ → ᄧ -->
+ <item first="0x1107" second="0x110e" result="0x1128"/> <!-- ᄇ + ᄎ → ᄨ -->
+ <item first="0x1107" second="0x110f" result="0xa973"/> <!-- ᄇ + ᄏ → ꥳ -->
+ <item first="0x1107" second="0x1110" result="0x1129"/> <!-- ᄇ + ᄐ → ᄩ -->
+ <item first="0x1107" second="0x1111" result="0x112a"/> <!-- ᄇ + ᄑ → ᄪ -->
+ <item first="0x1107" second="0x1112" result="0xa974"/> <!-- ᄇ + ᄒ → ꥴ -->
+ <item first="0x1107" second="0x112b" result="0x112c"/> <!-- ᄇ + ᄫ → ᄬ -->
+ <item first="0x1107" second="0x112d" result="0x1122"/> <!-- ᄇ + ᄭ → ᄢ -->
+ <item first="0x1107" second="0x112f" result="0x1123"/> <!-- ᄇ + ᄯ → ᄣ -->
+ <item first="0x1107" second="0x1132" result="0x1124"/> <!-- ᄇ + ᄲ → ᄤ -->
+ <item first="0x1107" second="0x1136" result="0x1126"/> <!-- ᄇ + ᄶ → ᄦ -->
+ <item first="0x1107" second="0x1139" result="0xa972"/> <!-- ᄇ + ᄹ → ꥲ -->
+ <item first="0x1108" second="0x110b" result="0x112c"/> <!-- ᄈ + ᄋ → ᄬ -->
+ <item first="0x1109" second="0x1100" result="0x112d"/> <!-- ᄉ + ᄀ → ᄭ -->
+ <item first="0x1109" second="0x1102" result="0x112e"/> <!-- ᄉ + ᄂ → ᄮ -->
+ <item first="0x1109" second="0x1103" result="0x112f"/> <!-- ᄉ + ᄃ → ᄯ -->
+ <item first="0x1109" second="0x1105" result="0x1130"/> <!-- ᄉ + ᄅ → ᄰ -->
+ <item first="0x1109" second="0x1106" result="0x1131"/> <!-- ᄉ + ᄆ → ᄱ -->
+ <item first="0x1109" second="0x1107" result="0x1132"/> <!-- ᄉ + ᄇ → ᄲ -->
+ <item first="0x1109" second="0x1109" result="0x110a"/> <!-- ᄉ + ᄉ → ᄊ -->
+ <item first="0x1109" second="0x110a" result="0x1134"/> <!-- ᄉ + ᄊ → ᄴ -->
+ <item first="0x1109" second="0x110b" result="0x1135"/> <!-- ᄉ + ᄋ → ᄵ -->
+ <item first="0x1109" second="0x110c" result="0x1136"/> <!-- ᄉ + ᄌ → ᄶ -->
+ <item first="0x1109" second="0x110e" result="0x1137"/> <!-- ᄉ + ᄎ → ᄷ -->
+ <item first="0x1109" second="0x110f" result="0x1138"/> <!-- ᄉ + ᄏ → ᄸ -->
+ <item first="0x1109" second="0x1110" result="0x1139"/> <!-- ᄉ + ᄐ → ᄹ -->
+ <item first="0x1109" second="0x1111" result="0x113a"/> <!-- ᄉ + ᄑ → ᄺ -->
+ <item first="0x1109" second="0x1112" result="0x113b"/> <!-- ᄉ + ᄒ → ᄻ -->
+ <item first="0x1109" second="0x111e" result="0x1133"/> <!-- ᄉ + ᄞ → ᄳ -->
+ <item first="0x1109" second="0x1132" result="0xa975"/> <!-- ᄉ + ᄲ → ꥵ -->
+ <item first="0x110a" second="0x1107" result="0xa975"/> <!-- ᄊ + ᄇ → ꥵ -->
+ <item first="0x110a" second="0x1109" result="0x1134"/> <!-- ᄊ + ᄉ → ᄴ -->
+ <item first="0x110b" second="0x1100" result="0x1141"/> <!-- ᄋ + ᄀ → ᅁ -->
+ <item first="0x110b" second="0x1103" result="0x1142"/> <!-- ᄋ + ᄃ → ᅂ -->
+ <item first="0x110b" second="0x1105" result="0xa976"/> <!-- ᄋ + ᄅ → ꥶ -->
+ <item first="0x110b" second="0x1106" result="0x1143"/> <!-- ᄋ + ᄆ → ᅃ -->
+ <item first="0x110b" second="0x1107" result="0x1144"/> <!-- ᄋ + ᄇ → ᅄ -->
+ <item first="0x110b" second="0x1109" result="0x1145"/> <!-- ᄋ + ᄉ → ᅅ -->
+ <item first="0x110b" second="0x110b" result="0x1147"/> <!-- ᄋ + ᄋ → ᅇ -->
+ <item first="0x110b" second="0x110c" result="0x1148"/> <!-- ᄋ + ᄌ → ᅈ -->
+ <item first="0x110b" second="0x110e" result="0x1149"/> <!-- ᄋ + ᄎ → ᅉ -->
+ <item first="0x110b" second="0x1110" result="0x114a"/> <!-- ᄋ + ᄐ → ᅊ -->
+ <item first="0x110b" second="0x1111" result="0x114b"/> <!-- ᄋ + ᄑ → ᅋ -->
+ <item first="0x110b" second="0x1112" result="0xa977"/> <!-- ᄋ + ᄒ → ꥷ -->
+ <item first="0x110b" second="0x1140" result="0x1146"/> <!-- ᄋ + ᅀ → ᅆ -->
+ <item first="0x110c" second="0x110b" result="0x114d"/> <!-- ᄌ + ᄋ → ᅍ -->
+ <item first="0x110c" second="0x110c" result="0x110d"/> <!-- ᄌ + ᄌ → ᄍ -->
+ <item first="0x110d" second="0x1112" result="0xa978"/> <!-- ᄍ + ᄒ → ꥸ -->
+ <item first="0x110e" second="0x110f" result="0x1152"/> <!-- ᄎ + ᄏ → ᅒ -->
+ <item first="0x110e" second="0x1112" result="0x1153"/> <!-- ᄎ + ᄒ → ᅓ -->
+ <item first="0x1110" second="0x1110" result="0xa979"/> <!-- ᄐ + ᄐ → ꥹ -->
+ <item first="0x1111" second="0x1107" result="0x1156"/> <!-- ᄑ + ᄇ → ᅖ -->
+ <item first="0x1111" second="0x110b" result="0x1157"/> <!-- ᄑ + ᄋ → ᅗ -->
+ <item first="0x1111" second="0x1112" result="0xa97a"/> <!-- ᄑ + ᄒ → ꥺ -->
+ <item first="0x1112" second="0x1109" result="0xa97b"/> <!-- ᄒ + ᄉ → ꥻ -->
+ <item first="0x1112" second="0x1112" result="0x1158"/> <!-- ᄒ + ᄒ → ᅘ -->
+ <item first="0x1121" second="0x1100" result="0x1122"/> <!-- ᄡ + ᄀ → ᄢ -->
+ <item first="0x1121" second="0x1103" result="0x1123"/> <!-- ᄡ + ᄃ → ᄣ -->
+ <item first="0x1121" second="0x1107" result="0x1124"/> <!-- ᄡ + ᄇ → ᄤ -->
+ <item first="0x1121" second="0x1109" result="0x1125"/> <!-- ᄡ + ᄉ → ᄥ -->
+ <item first="0x1121" second="0x110c" result="0x1126"/> <!-- ᄡ + ᄌ → ᄦ -->
+ <item first="0x1121" second="0x1110" result="0xa972"/> <!-- ᄡ + ᄐ → ꥲ -->
+ <item first="0x1132" second="0x1100" result="0x1133"/> <!-- ᄲ + ᄀ → ᄳ -->
+ <item first="0x113c" second="0x113c" result="0x113d"/> <!-- ᄼ + ᄼ → ᄽ -->
+ <item first="0x113e" second="0x113e" result="0x113f"/> <!-- ᄾ + ᄾ → ᄿ -->
+ <item first="0x114e" second="0x114e" result="0x114f"/> <!-- ᅎ + ᅎ → ᅏ -->
+ <item first="0x1150" second="0x1150" result="0x1151"/> <!-- ᅐ + ᅐ → ᅑ -->
+ <item first="0x1159" second="0x1159" result="0xa97c"/> <!-- ᅙ + ᅙ → ꥼ -->
+ <item first="0x1161" second="0x1161" result="0x119e"/> <!-- ᅡ + ᅡ → ᆞ -->
+ <item first="0x1161" second="0x1169" result="0x1176"/> <!-- ᅡ + ᅩ → ᅶ -->
+ <item first="0x1161" second="0x116e" result="0x1177"/> <!-- ᅡ + ᅮ → ᅷ -->
+ <item first="0x1161" second="0x1173" result="0x11a3"/> <!-- ᅡ + ᅳ → ᆣ -->
+ <item first="0x1161" second="0x1175" result="0x1162"/> <!-- ᅡ + ᅵ → ᅢ -->
+ <item first="0x1163" second="0x1169" result="0x1178"/> <!-- ᅣ + ᅩ → ᅸ -->
+ <item first="0x1163" second="0x116d" result="0x1179"/> <!-- ᅣ + ᅭ → ᅹ -->
+ <item first="0x1163" second="0x116e" result="0x11a4"/> <!-- ᅣ + ᅮ → ᆤ -->
+ <item first="0x1163" second="0x1175" result="0x1164"/> <!-- ᅣ + ᅵ → ᅤ -->
+ <item first="0x1165" second="0x1169" result="0x117a"/> <!-- ᅥ + ᅩ → ᅺ -->
+ <item first="0x1165" second="0x116e" result="0x117b"/> <!-- ᅥ + ᅮ → ᅻ -->
+ <item first="0x1165" second="0x1173" result="0x117c"/> <!-- ᅥ + ᅳ → ᅼ -->
+ <item first="0x1165" second="0x1175" result="0x1166"/> <!-- ᅥ + ᅵ → ᅦ -->
+ <item first="0x1167" second="0x1163" result="0x11a5"/> <!-- ᅧ + ᅣ → ᆥ -->
+ <item first="0x1167" second="0x1169" result="0x117d"/> <!-- ᅧ + ᅩ → ᅽ -->
+ <item first="0x1167" second="0x116e" result="0x117e"/> <!-- ᅧ + ᅮ → ᅾ -->
+ <item first="0x1167" second="0x1175" result="0x1168"/> <!-- ᅧ + ᅵ → ᅨ -->
+ <item first="0x1169" second="0x1161" result="0x116a"/> <!-- ᅩ + ᅡ → ᅪ -->
+ <item first="0x1169" second="0x1162" result="0x116b"/> <!-- ᅩ + ᅢ → ᅫ -->
+ <item first="0x1169" second="0x1163" result="0x11a6"/> <!-- ᅩ + ᅣ → ᆦ -->
+ <item first="0x1169" second="0x1164" result="0x11a7"/> <!-- ᅩ + ᅤ → ᆧ -->
+ <item first="0x1169" second="0x1165" result="0x117f"/> <!-- ᅩ + ᅥ → ᅿ -->
+ <item first="0x1169" second="0x1166" result="0x1180"/> <!-- ᅩ + ᅦ → ᆀ -->
+ <item first="0x1169" second="0x1167" result="0xd7b0"/> <!-- ᅩ + ᅧ → ힰ -->
+ <item first="0x1169" second="0x1168" result="0x1181"/> <!-- ᅩ + ᅨ → ᆁ -->
+ <item first="0x1169" second="0x1169" result="0x1182"/> <!-- ᅩ + ᅩ → ᆂ -->
+ <item first="0x1169" second="0x116e" result="0x1183"/> <!-- ᅩ + ᅮ → ᆃ -->
+ <item first="0x1169" second="0x1175" result="0x116c"/> <!-- ᅩ + ᅵ → ᅬ -->
+ <item first="0x116a" second="0x1175" result="0x116b"/> <!-- ᅪ + ᅵ → ᅫ -->
+ <item first="0x116d" second="0x1161" result="0xd7b2"/> <!-- ᅭ + ᅡ → ힲ -->
+ <item first="0x116d" second="0x1162" result="0xd7b3"/> <!-- ᅭ + ᅢ → ힳ -->
+ <item first="0x116d" second="0x1163" result="0x1184"/> <!-- ᅭ + ᅣ → ᆄ -->
+ <item first="0x116d" second="0x1164" result="0x1185"/> <!-- ᅭ + ᅤ → ᆅ -->
+ <item first="0x116d" second="0x1165" result="0xd7b4"/> <!-- ᅭ + ᅥ → ힴ -->
+ <item first="0x116d" second="0x1167" result="0x1186"/> <!-- ᅭ + ᅧ → ᆆ -->
+ <item first="0x116d" second="0x1169" result="0x1187"/> <!-- ᅭ + ᅩ → ᆇ -->
+ <item first="0x116d" second="0x1175" result="0x1188"/> <!-- ᅭ + ᅵ → ᆈ -->
+ <item first="0x116e" second="0x1161" result="0x1189"/> <!-- ᅮ + ᅡ → ᆉ -->
+ <item first="0x116e" second="0x1162" result="0x118a"/> <!-- ᅮ + ᅢ → ᆊ -->
+ <item first="0x116e" second="0x1165" result="0x116f"/> <!-- ᅮ + ᅥ → ᅯ -->
+ <item first="0x116e" second="0x1166" result="0x1170"/> <!-- ᅮ + ᅦ → ᅰ -->
+ <item first="0x116e" second="0x1167" result="0xd7b5"/> <!-- ᅮ + ᅧ → ힵ -->
+ <item first="0x116e" second="0x1168" result="0x118c"/> <!-- ᅮ + ᅨ → ᆌ -->
+ <item first="0x116e" second="0x116e" result="0x118d"/> <!-- ᅮ + ᅮ → ᆍ -->
+ <item first="0x116e" second="0x1175" result="0x1171"/> <!-- ᅮ + ᅵ → ᅱ -->
+ <item first="0x116e" second="0x117c" result="0x118b"/> <!-- ᅮ + ᅼ → ᆋ -->
+ <item first="0x116e" second="0xd7c4" result="0xd7b6"/> <!-- ᅮ + ퟄ → ힶ -->
+ <item first="0x116f" second="0x1173" result="0x118b"/> <!-- ᅯ + ᅳ → ᆋ -->
+ <item first="0x116f" second="0x1175" result="0x1170"/> <!-- ᅯ + ᅵ → ᅰ -->
+ <item first="0x1171" second="0x1175" result="0xd7b6"/> <!-- ᅱ + ᅵ → ힶ -->
+ <item first="0x1172" second="0x1161" result="0x118e"/> <!-- ᅲ + ᅡ → ᆎ -->
+ <item first="0x1172" second="0x1162" result="0xd7b7"/> <!-- ᅲ + ᅢ → ힷ -->
+ <item first="0x1172" second="0x1165" result="0x118f"/> <!-- ᅲ + ᅥ → ᆏ -->
+ <item first="0x1172" second="0x1166" result="0x1190"/> <!-- ᅲ + ᅦ → ᆐ -->
+ <item first="0x1172" second="0x1167" result="0x1191"/> <!-- ᅲ + ᅧ → ᆑ -->
+ <item first="0x1172" second="0x1168" result="0x1192"/> <!-- ᅲ + ᅨ → ᆒ -->
+ <item first="0x1172" second="0x1169" result="0xd7b8"/> <!-- ᅲ + ᅩ → ힸ -->
+ <item first="0x1172" second="0x116e" result="0x1193"/> <!-- ᅲ + ᅮ → ᆓ -->
+ <item first="0x1172" second="0x1175" result="0x1194"/> <!-- ᅲ + ᅵ → ᆔ -->
+ <item first="0x1173" second="0x1161" result="0xd7b9"/> <!-- ᅳ + ᅡ → ힹ -->
+ <item first="0x1173" second="0x1165" result="0xd7ba"/> <!-- ᅳ + ᅥ → ힺ -->
+ <item first="0x1173" second="0x1166" result="0xd7bb"/> <!-- ᅳ + ᅦ → ힻ -->
+ <item first="0x1173" second="0x1169" result="0xd7bc"/> <!-- ᅳ + ᅩ → ힼ -->
+ <item first="0x1173" second="0x116e" result="0x1195"/> <!-- ᅳ + ᅮ → ᆕ -->
+ <item first="0x1173" second="0x1173" result="0x1196"/> <!-- ᅳ + ᅳ → ᆖ -->
+ <item first="0x1173" second="0x1175" result="0x1174"/> <!-- ᅳ + ᅵ → ᅴ -->
+ <item first="0x1174" second="0x116e" result="0x1197"/> <!-- ᅴ + ᅮ → ᆗ -->
+ <item first="0x1175" second="0x1161" result="0x1198"/> <!-- ᅵ + ᅡ → ᆘ -->
+ <item first="0x1175" second="0x1163" result="0x1199"/> <!-- ᅵ + ᅣ → ᆙ -->
+ <item first="0x1175" second="0x1164" result="0xd7be"/> <!-- ᅵ + ᅤ → ힾ -->
+ <item first="0x1175" second="0x1167" result="0xd7bf"/> <!-- ᅵ + ᅧ → ힿ -->
+ <item first="0x1175" second="0x1168" result="0xd7c0"/> <!-- ᅵ + ᅨ → ퟀ -->
+ <item first="0x1175" second="0x1169" result="0x119a"/> <!-- ᅵ + ᅩ → ᆚ -->
+ <item first="0x1175" second="0x116d" result="0xd7c2"/> <!-- ᅵ + ᅭ → ퟂ -->
+ <item first="0x1175" second="0x116e" result="0x119b"/> <!-- ᅵ + ᅮ → ᆛ -->
+ <item first="0x1175" second="0x1172" result="0xd7c3"/> <!-- ᅵ + ᅲ → ퟃ -->
+ <item first="0x1175" second="0x1173" result="0x119c"/> <!-- ᅵ + ᅳ → ᆜ -->
+ <item first="0x1175" second="0x1175" result="0xd7c4"/> <!-- ᅵ + ᅵ → ퟄ -->
+ <item first="0x1175" second="0x1178" result="0xd7bd"/> <!-- ᅵ + ᅸ → ힽ -->
+ <item first="0x1175" second="0x119e" result="0x119d"/> <!-- ᅵ + ᆞ → ᆝ -->
+ <item first="0x1182" second="0x1175" result="0xd7b1"/> <!-- ᆂ + ᅵ → ힱ -->
+ <item first="0x1199" second="0x1169" result="0xd7bd"/> <!-- ᆙ + ᅩ → ힽ -->
+ <item first="0x119a" second="0x1175" result="0xd7c1"/> <!-- ᆚ + ᅵ → ퟁ -->
+ <item first="0x119e" second="0x1161" result="0xd7c5"/> <!-- ᆞ + ᅡ → ퟅ -->
+ <item first="0x119e" second="0x1165" result="0x119f"/> <!-- ᆞ + ᅥ → ᆟ -->
+ <item first="0x119e" second="0x1166" result="0xd7c6"/> <!-- ᆞ + ᅦ → ퟆ -->
+ <item first="0x119e" second="0x116e" result="0x11a0"/> <!-- ᆞ + ᅮ → ᆠ -->
+ <item first="0x119e" second="0x1175" result="0x11a1"/> <!-- ᆞ + ᅵ → ᆡ -->
+ <item first="0x119e" second="0x119e" result="0x11a2"/> <!-- ᆞ + ᆞ → ᆢ -->
+ <item first="0x11a8" second="0x11a8" result="0x11a9"/> <!-- ᆨ + ᆨ → ᆩ -->
+ <item first="0x11a8" second="0x11ab" result="0x11fa"/> <!-- ᆨ + ᆫ → ᇺ -->
+ <item first="0x11a8" second="0x11af" result="0x11c3"/> <!-- ᆨ + ᆯ → ᇃ -->
+ <item first="0x11a8" second="0x11b8" result="0x11fb"/> <!-- ᆨ + ᆸ → ᇻ -->
+ <item first="0x11a8" second="0x11ba" result="0x11aa"/> <!-- ᆨ + ᆺ → ᆪ -->
+ <item first="0x11a8" second="0x11be" result="0x11fc"/> <!-- ᆨ + ᆾ → ᇼ -->
+ <item first="0x11a8" second="0x11bf" result="0x11fd"/> <!-- ᆨ + ᆿ → ᇽ -->
+ <item first="0x11a8" second="0x11c2" result="0x11fe"/> <!-- ᆨ + ᇂ → ᇾ -->
+ <item first="0x11a8" second="0x11e7" result="0x11c4"/> <!-- ᆨ + ᇧ → ᇄ -->
+ <item first="0x11aa" second="0x11a8" result="0x11c4"/> <!-- ᆪ + ᆨ → ᇄ -->
+ <item first="0x11ab" second="0x11a8" result="0x11c5"/> <!-- ᆫ + ᆨ → ᇅ -->
+ <item first="0x11ab" second="0x11ab" result="0x11ff"/> <!-- ᆫ + ᆫ → ᇿ -->
+ <item first="0x11ab" second="0x11ae" result="0x11c6"/> <!-- ᆫ + ᆮ → ᇆ -->
+ <item first="0x11ab" second="0x11af" result="0xd7cb"/> <!-- ᆫ + ᆯ → ퟋ -->
+ <item first="0x11ab" second="0x11ba" result="0x11c7"/> <!-- ᆫ + ᆺ → ᇇ -->
+ <item first="0x11ab" second="0x11bd" result="0x11ac"/> <!-- ᆫ + ᆽ → ᆬ -->
+ <item first="0x11ab" second="0x11be" result="0xd7cc"/> <!-- ᆫ + ᆾ → ퟌ -->
+ <item first="0x11ab" second="0x11c0" result="0x11c9"/> <!-- ᆫ + ᇀ → ᇉ -->
+ <item first="0x11ab" second="0x11c2" result="0x11ad"/> <!-- ᆫ + ᇂ → ᆭ -->
+ <item first="0x11ab" second="0x11eb" result="0x11c8"/> <!-- ᆫ + ᇫ → ᇈ -->
+ <item first="0x11ae" second="0x11a8" result="0x11ca"/> <!-- ᆮ + ᆨ → ᇊ -->
+ <item first="0x11ae" second="0x11ae" result="0xd7cd"/> <!-- ᆮ + ᆮ → ퟍ -->
+ <item first="0x11ae" second="0x11af" result="0x11cb"/> <!-- ᆮ + ᆯ → ᇋ -->
+ <item first="0x11ae" second="0x11b8" result="0xd7cf"/> <!-- ᆮ + ᆸ → ퟏ -->
+ <item first="0x11ae" second="0x11ba" result="0xd7d0"/> <!-- ᆮ + ᆺ → ퟐ -->
+ <item first="0x11ae" second="0x11bd" result="0xd7d2"/> <!-- ᆮ + ᆽ → ퟒ -->
+ <item first="0x11ae" second="0x11be" result="0xd7d3"/> <!-- ᆮ + ᆾ → ퟓ -->
+ <item first="0x11ae" second="0x11c0" result="0xd7d4"/> <!-- ᆮ + ᇀ → ퟔ -->
+ <item first="0x11ae" second="0x11e7" result="0xd7d1"/> <!-- ᆮ + ᇧ → ퟑ -->
+ <item first="0x11ae" second="0xd7cf" result="0xd7ce"/> <!-- ᆮ + ퟏ → ퟎ -->
+ <item first="0x11af" second="0x11a8" result="0x11b0"/> <!-- ᆯ + ᆨ → ᆰ -->
+ <item first="0x11af" second="0x11a9" result="0xd7d5"/> <!-- ᆯ + ᆩ → ퟕ -->
+ <item first="0x11af" second="0x11aa" result="0x11cc"/> <!-- ᆯ + ᆪ → ᇌ -->
+ <item first="0x11af" second="0x11ab" result="0x11cd"/> <!-- ᆯ + ᆫ → ᇍ -->
+ <item first="0x11af" second="0x11ae" result="0x11ce"/> <!-- ᆯ + ᆮ → ᇎ -->
+ <item first="0x11af" second="0x11af" result="0x11d0"/> <!-- ᆯ + ᆯ → ᇐ -->
+ <item first="0x11af" second="0x11b7" result="0x11b1"/> <!-- ᆯ + ᆷ → ᆱ -->
+ <item first="0x11af" second="0x11b8" result="0x11b2"/> <!-- ᆯ + ᆸ → ᆲ -->
+ <item first="0x11af" second="0x11b9" result="0x11d3"/> <!-- ᆯ + ᆹ → ᇓ -->
+ <item first="0x11af" second="0x11ba" result="0x11b3"/> <!-- ᆯ + ᆺ → ᆳ -->
+ <item first="0x11af" second="0x11bb" result="0x11d6"/> <!-- ᆯ + ᆻ → ᇖ -->
+ <item first="0x11af" second="0x11bc" result="0xd7dd"/> <!-- ᆯ + ᆼ → ퟝ -->
+ <item first="0x11af" second="0x11bf" result="0x11d8"/> <!-- ᆯ + ᆿ → ᇘ -->
+ <item first="0x11af" second="0x11c0" result="0x11b4"/> <!-- ᆯ + ᇀ → ᆴ -->
+ <item first="0x11af" second="0x11c1" result="0x11b5"/> <!-- ᆯ + ᇁ → ᆵ -->
+ <item first="0x11af" second="0x11c2" result="0x11b6"/> <!-- ᆯ + ᇂ → ᆶ -->
+ <item first="0x11af" second="0x11d8" result="0xd7d7"/> <!-- ᆯ + ᇘ → ퟗ -->
+ <item first="0x11af" second="0x11da" result="0x11d1"/> <!-- ᆯ + ᇚ → ᇑ -->
+ <item first="0x11af" second="0x11dd" result="0x11d2"/> <!-- ᆯ + ᇝ → ᇒ -->
+ <item first="0x11af" second="0x11e1" result="0xd7d8"/> <!-- ᆯ + ᇡ → ퟘ -->
+ <item first="0x11af" second="0x11e4" result="0xd7da"/> <!-- ᆯ + ᇤ → ퟚ -->
+ <item first="0x11af" second="0x11e5" result="0x11d4"/> <!-- ᆯ + ᇥ → ᇔ -->
+ <item first="0x11af" second="0x11e6" result="0x11d5"/> <!-- ᆯ + ᇦ → ᇕ -->
+ <item first="0x11af" second="0x11eb" result="0x11d7"/> <!-- ᆯ + ᇫ → ᇗ -->
+ <item first="0x11af" second="0x11f0" result="0xd7db"/> <!-- ᆯ + ᇰ → ퟛ -->
+ <item first="0x11af" second="0x11f9" result="0x11d9"/> <!-- ᆯ + ᇹ → ᇙ -->
+ <item first="0x11af" second="0x11fe" result="0xd7d6"/> <!-- ᆯ + ᇾ → ퟖ -->
+ <item first="0x11af" second="0xd7e3" result="0xd7d9"/> <!-- ᆯ + ퟣ → ퟙ -->
+ <item first="0x11b0" second="0x11a8" result="0xd7d5"/> <!-- ᆰ + ᆨ → ퟕ -->
+ <item first="0x11b0" second="0x11ba" result="0x11cc"/> <!-- ᆰ + ᆺ → ᇌ -->
+ <item first="0x11b0" second="0x11c2" result="0xd7d6"/> <!-- ᆰ + ᇂ → ퟖ -->
+ <item first="0x11b1" second="0x11a8" result="0x11d1"/> <!-- ᆱ + ᆨ → ᇑ -->
+ <item first="0x11b1" second="0x11ba" result="0x11d2"/> <!-- ᆱ + ᆺ → ᇒ -->
+ <item first="0x11b1" second="0x11c2" result="0xd7d8"/> <!-- ᆱ + ᇂ → ퟘ -->
+ <item first="0x11b2" second="0x11ae" result="0xd7d9"/> <!-- ᆲ + ᆮ → ퟙ -->
+ <item first="0x11b2" second="0x11ba" result="0x11d3"/> <!-- ᆲ + ᆺ → ᇓ -->
+ <item first="0x11b2" second="0x11bc" result="0x11d5"/> <!-- ᆲ + ᆼ → ᇕ -->
+ <item first="0x11b2" second="0x11c1" result="0xd7da"/> <!-- ᆲ + ᇁ → ퟚ -->
+ <item first="0x11b2" second="0x11c2" result="0x11d4"/> <!-- ᆲ + ᇂ → ᇔ -->
+ <item first="0x11b3" second="0x11ba" result="0x11d6"/> <!-- ᆳ + ᆺ → ᇖ -->
+ <item first="0x11b7" second="0x11a8" result="0x11da"/> <!-- ᆷ + ᆨ → ᇚ -->
+ <item first="0x11b7" second="0x11ab" result="0xd7de"/> <!-- ᆷ + ᆫ → ퟞ -->
+ <item first="0x11b7" second="0x11af" result="0x11db"/> <!-- ᆷ + ᆯ → ᇛ -->
+ <item first="0x11b7" second="0x11b7" result="0xd7e0"/> <!-- ᆷ + ᆷ → ퟠ -->
+ <item first="0x11b7" second="0x11b8" result="0x11dc"/> <!-- ᆷ + ᆸ → ᇜ -->
+ <item first="0x11b7" second="0x11b9" result="0xd7e1"/> <!-- ᆷ + ᆹ → ퟡ -->
+ <item first="0x11b7" second="0x11ba" result="0x11dd"/> <!-- ᆷ + ᆺ → ᇝ -->
+ <item first="0x11b7" second="0x11bb" result="0x11de"/> <!-- ᆷ + ᆻ → ᇞ -->
+ <item first="0x11b7" second="0x11bc" result="0x11e2"/> <!-- ᆷ + ᆼ → ᇢ -->
+ <item first="0x11b7" second="0x11bd" result="0xd7e2"/> <!-- ᆷ + ᆽ → ퟢ -->
+ <item first="0x11b7" second="0x11be" result="0x11e0"/> <!-- ᆷ + ᆾ → ᇠ -->
+ <item first="0x11b7" second="0x11c2" result="0x11e1"/> <!-- ᆷ + ᇂ → ᇡ -->
+ <item first="0x11b7" second="0x11eb" result="0x11df"/> <!-- ᆷ + ᇫ → ᇟ -->
+ <item first="0x11b7" second="0x11ff" result="0xd7df"/> <!-- ᆷ + ᇿ → ퟟ -->
+ <item first="0x11b8" second="0x11ae" result="0xd7e3"/> <!-- ᆸ + ᆮ → ퟣ -->
+ <item first="0x11b8" second="0x11af" result="0x11e3"/> <!-- ᆸ + ᆯ → ᇣ -->
+ <item first="0x11b8" second="0x11b5" result="0xd7e4"/> <!-- ᆸ + ᆵ → ퟤ -->
+ <item first="0x11b8" second="0x11b7" result="0xd7e5"/> <!-- ᆸ + ᆷ → ퟥ -->
+ <item first="0x11b8" second="0x11b8" result="0xd7e6"/> <!-- ᆸ + ᆸ → ퟦ -->
+ <item first="0x11b8" second="0x11ba" result="0x11b9"/> <!-- ᆸ + ᆺ → ᆹ -->
+ <item first="0x11b8" second="0x11bc" result="0x11e6"/> <!-- ᆸ + ᆼ → ᇦ -->
+ <item first="0x11b8" second="0x11bd" result="0xd7e8"/> <!-- ᆸ + ᆽ → ퟨ -->
+ <item first="0x11b8" second="0x11be" result="0xd7e9"/> <!-- ᆸ + ᆾ → ퟩ -->
+ <item first="0x11b8" second="0x11c1" result="0x11e4"/> <!-- ᆸ + ᇁ → ᇤ -->
+ <item first="0x11b8" second="0x11c2" result="0x11e5"/> <!-- ᆸ + ᇂ → ᇥ -->
+ <item first="0x11b8" second="0x11e8" result="0xd7e7"/> <!-- ᆸ + ᇨ → ퟧ -->
+ <item first="0x11b9" second="0x11ae" result="0xd7e7"/> <!-- ᆹ + ᆮ → ퟧ -->
+ <item first="0x11ba" second="0x11a8" result="0x11e7"/> <!-- ᆺ + ᆨ → ᇧ -->
+ <item first="0x11ba" second="0x11ae" result="0x11e8"/> <!-- ᆺ + ᆮ → ᇨ -->
+ <item first="0x11ba" second="0x11af" result="0x11e9"/> <!-- ᆺ + ᆯ → ᇩ -->
+ <item first="0x11ba" second="0x11b7" result="0xd7ea"/> <!-- ᆺ + ᆷ → ퟪ -->
+ <item first="0x11ba" second="0x11b8" result="0x11ea"/> <!-- ᆺ + ᆸ → ᇪ -->
+ <item first="0x11ba" second="0x11ba" result="0x11bb"/> <!-- ᆺ + ᆺ → ᆻ -->
+ <item first="0x11ba" second="0x11bd" result="0xd7ef"/> <!-- ᆺ + ᆽ → ퟯ -->
+ <item first="0x11ba" second="0x11be" result="0xd7f0"/> <!-- ᆺ + ᆾ → ퟰ -->
+ <item first="0x11ba" second="0x11c0" result="0xd7f1"/> <!-- ᆺ + ᇀ → ퟱ -->
+ <item first="0x11ba" second="0x11c2" result="0xd7f2"/> <!-- ᆺ + ᇂ → ퟲ -->
+ <item first="0x11ba" second="0x11e6" result="0xd7eb"/> <!-- ᆺ + ᇦ → ퟫ -->
+ <item first="0x11ba" second="0x11e7" result="0xd7ec"/> <!-- ᆺ + ᇧ → ퟬ -->
+ <item first="0x11ba" second="0x11e8" result="0xd7ed"/> <!-- ᆺ + ᇨ → ퟭ -->
+ <item first="0x11ba" second="0x11eb" result="0xd7ee"/> <!-- ᆺ + ᇫ → ퟮ -->
+ <item first="0x11bb" second="0x11a8" result="0xd7ec"/> <!-- ᆻ + ᆨ → ퟬ -->
+ <item first="0x11bb" second="0x11ae" result="0xd7ed"/> <!-- ᆻ + ᆮ → ퟭ -->
+ <item first="0x11bd" second="0x11b8" result="0xd7f7"/> <!-- ᆽ + ᆸ → ퟷ -->
+ <item first="0x11bd" second="0x11bd" result="0xd7f9"/> <!-- ᆽ + ᆽ → ퟹ -->
+ <item first="0x11bd" second="0xd7e6" result="0xd7f8"/> <!-- ᆽ + ퟦ → ퟸ -->
+ <item first="0x11c1" second="0x11b8" result="0x11f3"/> <!-- ᇁ + ᆸ → ᇳ -->
+ <item first="0x11c1" second="0x11ba" result="0xd7fa"/> <!-- ᇁ + ᆺ → ퟺ -->
+ <item first="0x11c1" second="0x11bc" result="0x11f4"/> <!-- ᇁ + ᆼ → ᇴ -->
+ <item first="0x11c1" second="0x11c0" result="0xd7fb"/> <!-- ᇁ + ᇀ → ퟻ -->
+ <item first="0x11c2" second="0x11ab" result="0x11f5"/> <!-- ᇂ + ᆫ → ᇵ -->
+ <item first="0x11c2" second="0x11af" result="0x11f6"/> <!-- ᇂ + ᆯ → ᇶ -->
+ <item first="0x11c2" second="0x11b7" result="0x11f7"/> <!-- ᇂ + ᆷ → ᇷ -->
+ <item first="0x11c2" second="0x11b8" result="0x11f8"/> <!-- ᇂ + ᆸ → ᇸ -->
+ <item first="0x11ce" second="0x11c2" result="0x11cf"/> <!-- ᇎ + ᇂ → ᇏ -->
+ <item first="0x11d0" second="0x11bf" result="0xd7d7"/> <!-- ᇐ + ᆿ → ퟗ -->
+ <item first="0x11d9" second="0x11c2" result="0xd7dc"/> <!-- ᇙ + ᇂ → ퟜ -->
+ <item first="0x11dc" second="0x11ba" result="0xd7e1"/> <!-- ᇜ + ᆺ → ퟡ -->
+ <item first="0x11dd" second="0x11ba" result="0x11de"/> <!-- ᇝ + ᆺ → ᇞ -->
+ <item first="0x11e3" second="0x11c1" result="0xd7e4"/> <!-- ᇣ + ᇁ → ퟤ -->
+ <item first="0x11ea" second="0x11bc" result="0xd7eb"/> <!-- ᇪ + ᆼ → ퟫ -->
+ <item first="0x11eb" second="0x11b8" result="0xd7f3"/> <!-- ᇫ + ᆸ → ퟳ -->
+ <item first="0x11eb" second="0x11e6" result="0xd7f4"/> <!-- ᇫ + ᇦ → ퟴ -->
+ <item first="0x11ec" second="0x11a8" result="0x11ed"/> <!-- ᇬ + ᆨ → ᇭ -->
+ <item first="0x11f0" second="0x11a8" result="0x11ec"/> <!-- ᇰ + ᆨ → ᇬ -->
+ <item first="0x11f0" second="0x11a9" result="0x11ed"/> <!-- ᇰ + ᆩ → ᇭ -->
+ <item first="0x11f0" second="0x11b7" result="0xd7f5"/> <!-- ᇰ + ᆷ → ퟵ -->
+ <item first="0x11f0" second="0x11ba" result="0x11f1"/> <!-- ᇰ + ᆺ → ᇱ -->
+ <item first="0x11f0" second="0x11bf" result="0x11ef"/> <!-- ᇰ + ᆿ → ᇯ -->
+ <item first="0x11f0" second="0x11c2" result="0xd7f6"/> <!-- ᇰ + ᇂ → ퟶ -->
+ <item first="0x11f0" second="0x11eb" result="0x11f2"/> <!-- ᇰ + ᇫ → ᇲ -->
+ <item first="0x11f0" second="0x11f0" result="0x11ee"/> <!-- ᇰ + ᇰ → ᇮ -->
+ <item first="0xa964" second="0x1100" result="0xa965"/> <!-- ꥤ + ᄀ → ꥥ -->
+ <item first="0xa966" second="0x1103" result="0xa967"/> <!-- ꥦ + ᄃ → ꥧ -->
+ <item first="0xa969" second="0x1107" result="0xa96a"/> <!-- ꥩ + ᄇ → ꥪ -->
+ <item first="0xa969" second="0x110b" result="0xa96b"/> <!-- ꥩ + ᄋ → ꥫ -->
+ <item first="0xd7c5" second="0x1161" result="0x11a2"/> <!-- ퟅ + ᅡ → ᆢ -->
+ <item first="0xd7cd" second="0x11b8" result="0xd7ce"/> <!-- ퟍ + ᆸ → ퟎ -->
+ <item first="0xd7d0" second="0x11a8" result="0xd7d1"/> <!-- ퟐ + ᆨ → ퟑ -->
+ <item first="0xd7de" second="0x11ab" result="0xd7df"/> <!-- ퟞ + ᆫ → ퟟ -->
+ <item first="0xd7f3" second="0x11bc" result="0xd7f4"/> <!-- ퟳ + ᆼ → ퟴ -->
+ <item first="0xd7f7" second="0x11b8" result="0xd7f8"/> <!-- ퟷ + ᆸ → ퟸ -->
+</combination>
diff --git a/data/keyboards/hangul-keyboard-2.xml.template b/data/keyboards/hangul-keyboard-2.xml.template
new file mode 100644
index 0000000..7704d08
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-2.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="2" type="jamo">
+
+ <_name>Dubeolsik</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x0021"/> <!-- ! → ! -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x0027"/> <!-- ' → ' -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x002f"/> <!-- / → / -->
+ <item key="0x30" value="0x0030"/> <!-- 0 → 0 -->
+ <item key="0x31" value="0x0031"/> <!-- 1 → 1 -->
+ <item key="0x32" value="0x0032"/> <!-- 2 → 2 -->
+ <item key="0x33" value="0x0033"/> <!-- 3 → 3 -->
+ <item key="0x34" value="0x0034"/> <!-- 4 → 4 -->
+ <item key="0x35" value="0x0035"/> <!-- 5 → 5 -->
+ <item key="0x36" value="0x0036"/> <!-- 6 → 6 -->
+ <item key="0x37" value="0x0037"/> <!-- 7 → 7 -->
+ <item key="0x38" value="0x0038"/> <!-- 8 → 8 -->
+ <item key="0x39" value="0x0039"/> <!-- 9 → 9 -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x003b"/> <!-- ; → ; -->
+ <item key="0x3c" value="0x003c"/> <!-- < → < -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x003e"/> <!-- > → > -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x1106"/> <!-- A → ᄆᅠ -->
+ <item key="0x42" value="0x1172"/> <!-- B → ᅟᅲ -->
+ <item key="0x43" value="0x110e"/> <!-- C → ᄎᅠ -->
+ <item key="0x44" value="0x110b"/> <!-- D → ᄋᅠ -->
+ <item key="0x45" value="0x1104"/> <!-- E → ᄄᅠ -->
+ <item key="0x46" value="0x1105"/> <!-- F → ᄅᅠ -->
+ <item key="0x47" value="0x1112"/> <!-- G → ᄒᅠ -->
+ <item key="0x48" value="0x1169"/> <!-- H → ᅟᅩ -->
+ <item key="0x49" value="0x1163"/> <!-- I → ᅟᅣ -->
+ <item key="0x4a" value="0x1165"/> <!-- J → ᅟᅥ -->
+ <item key="0x4b" value="0x1161"/> <!-- K → ᅟᅡ -->
+ <item key="0x4c" value="0x1175"/> <!-- L → ᅟᅵ -->
+ <item key="0x4d" value="0x1173"/> <!-- M → ᅟᅳ -->
+ <item key="0x4e" value="0x116e"/> <!-- N → ᅟᅮ -->
+ <item key="0x4f" value="0x1164"/> <!-- O → ᅟᅤ -->
+ <item key="0x50" value="0x1168"/> <!-- P → ᅟᅨ -->
+ <item key="0x51" value="0x1108"/> <!-- Q → ᄈᅠ -->
+ <item key="0x52" value="0x1101"/> <!-- R → ᄁᅠ -->
+ <item key="0x53" value="0x1102"/> <!-- S → ᄂᅠ -->
+ <item key="0x54" value="0x110a"/> <!-- T → ᄊᅠ -->
+ <item key="0x55" value="0x1167"/> <!-- U → ᅟᅧ -->
+ <item key="0x56" value="0x1111"/> <!-- V → ᄑᅠ -->
+ <item key="0x57" value="0x110d"/> <!-- W → ᄍᅠ -->
+ <item key="0x58" value="0x1110"/> <!-- X → ᄐᅠ -->
+ <item key="0x59" value="0x116d"/> <!-- Y → ᅟᅭ -->
+ <item key="0x5a" value="0x110f"/> <!-- Z → ᄏᅠ -->
+ <item key="0x5b" value="0x005b"/> <!-- [ → [ -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x005d"/> <!-- ] → ] -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x1106"/> <!-- a → ᄆᅠ -->
+ <item key="0x62" value="0x1172"/> <!-- b → ᅟᅲ -->
+ <item key="0x63" value="0x110e"/> <!-- c → ᄎᅠ -->
+ <item key="0x64" value="0x110b"/> <!-- d → ᄋᅠ -->
+ <item key="0x65" value="0x1103"/> <!-- e → ᄃᅠ -->
+ <item key="0x66" value="0x1105"/> <!-- f → ᄅᅠ -->
+ <item key="0x67" value="0x1112"/> <!-- g → ᄒᅠ -->
+ <item key="0x68" value="0x1169"/> <!-- h → ᅟᅩ -->
+ <item key="0x69" value="0x1163"/> <!-- i → ᅟᅣ -->
+ <item key="0x6a" value="0x1165"/> <!-- j → ᅟᅥ -->
+ <item key="0x6b" value="0x1161"/> <!-- k → ᅟᅡ -->
+ <item key="0x6c" value="0x1175"/> <!-- l → ᅟᅵ -->
+ <item key="0x6d" value="0x1173"/> <!-- m → ᅟᅳ -->
+ <item key="0x6e" value="0x116e"/> <!-- n → ᅟᅮ -->
+ <item key="0x6f" value="0x1162"/> <!-- o → ᅟᅢ -->
+ <item key="0x70" value="0x1166"/> <!-- p → ᅟᅦ -->
+ <item key="0x71" value="0x1107"/> <!-- q → ᄇᅠ -->
+ <item key="0x72" value="0x1100"/> <!-- r → ᄀᅠ -->
+ <item key="0x73" value="0x1102"/> <!-- s → ᄂᅠ -->
+ <item key="0x74" value="0x1109"/> <!-- t → ᄉᅠ -->
+ <item key="0x75" value="0x1167"/> <!-- u → ᅟᅧ -->
+ <item key="0x76" value="0x1111"/> <!-- v → ᄑᅠ -->
+ <item key="0x77" value="0x110c"/> <!-- w → ᄌᅠ -->
+ <item key="0x78" value="0x1110"/> <!-- x → ᄐᅠ -->
+ <item key="0x79" value="0x116d"/> <!-- y → ᅟᅭ -->
+ <item key="0x7a" value="0x110f"/> <!-- z → ᄏᅠ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x007e"/> <!-- ~ → ~ -->
+ </map>
+
+ <include file="hangul-combination-default.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-2y.xml.template b/data/keyboards/hangul-keyboard-2y.xml.template
new file mode 100644
index 0000000..6ff75e7
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-2y.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="2y" type="jamo-yet">
+
+ <_name>Dubeolsik Yetgeul</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x0021"/> <!-- ! → ! -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x0027"/> <!-- ' → ' -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x002f"/> <!-- / → / -->
+ <item key="0x30" value="0x0030"/> <!-- 0 → 0 -->
+ <item key="0x31" value="0x0031"/> <!-- 1 → 1 -->
+ <item key="0x32" value="0x0032"/> <!-- 2 → 2 -->
+ <item key="0x33" value="0x0033"/> <!-- 3 → 3 -->
+ <item key="0x34" value="0x0034"/> <!-- 4 → 4 -->
+ <item key="0x35" value="0x0035"/> <!-- 5 → 5 -->
+ <item key="0x36" value="0x0036"/> <!-- 6 → 6 -->
+ <item key="0x37" value="0x0037"/> <!-- 7 → 7 -->
+ <item key="0x38" value="0x0038"/> <!-- 8 → 8 -->
+ <item key="0x39" value="0x0039"/> <!-- 9 → 9 -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x003b"/> <!-- ; → ; -->
+ <item key="0x3c" value="0x003c"/> <!-- < → < -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x003e"/> <!-- > → > -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x1140"/> <!-- A → ᅀᅠ -->
+ <item key="0x42" value="0x1154"/> <!-- B → ᅔᅠ -->
+ <item key="0x43" value="0x114e"/> <!-- C → ᅎᅠ -->
+ <item key="0x44" value="0x114c"/> <!-- D → ᅌᅠ -->
+ <item key="0x45" value="0x1104"/> <!-- E → ᄄᅠ -->
+ <item key="0x46" value="0x111a"/> <!-- F → ᄚᅠ -->
+ <item key="0x47" value="0x1159"/> <!-- G → ᅙᅠ -->
+ <item key="0x48" value="0x1183"/> <!-- H → ᅟᆃ -->
+ <item key="0x49" value="0x1163"/> <!-- I → ᅟᅣ -->
+ <item key="0x4a" value="0x1165"/> <!-- J → ᅟᅥ -->
+ <item key="0x4b" value="0x119e"/> <!-- K → ᅟᆞ -->
+ <item key="0x4c" value="0x1194"/> <!-- L → ᅟᆔ -->
+ <item key="0x4d" value="0x1173"/> <!-- M → ᅟᅳ -->
+ <item key="0x4e" value="0x1155"/> <!-- N → ᅕᅠ -->
+ <item key="0x4f" value="0x1164"/> <!-- O → ᅟᅤ -->
+ <item key="0x50" value="0x1168"/> <!-- P → ᅟᅨ -->
+ <item key="0x51" value="0x1108"/> <!-- Q → ᄈᅠ -->
+ <item key="0x52" value="0x1101"/> <!-- R → ᄁᅠ -->
+ <item key="0x53" value="0x115d"/> <!-- S → ᅝᅠ -->
+ <item key="0x54" value="0x110a"/> <!-- T → ᄊᅠ -->
+ <item key="0x55" value="0x1167"/> <!-- U → ᅟᅧ -->
+ <item key="0x56" value="0x1150"/> <!-- V → ᅐᅠ -->
+ <item key="0x57" value="0x110d"/> <!-- W → ᄍᅠ -->
+ <item key="0x58" value="0x113e"/> <!-- X → ᄾᅠ -->
+ <item key="0x59" value="0x116d"/> <!-- Y → ᅟᅭ -->
+ <item key="0x5a" value="0x113c"/> <!-- Z → ᄼᅠ -->
+ <item key="0x5b" value="0x005b"/> <!-- [ → [ -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x005d"/> <!-- ] → ] -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x1106"/> <!-- a → ᄆᅠ -->
+ <item key="0x62" value="0x1172"/> <!-- b → ᅟᅲ -->
+ <item key="0x63" value="0x110e"/> <!-- c → ᄎᅠ -->
+ <item key="0x64" value="0x110b"/> <!-- d → ᄋᅠ -->
+ <item key="0x65" value="0x1103"/> <!-- e → ᄃᅠ -->
+ <item key="0x66" value="0x1105"/> <!-- f → ᄅᅠ -->
+ <item key="0x67" value="0x1112"/> <!-- g → ᄒᅠ -->
+ <item key="0x68" value="0x1169"/> <!-- h → ᅟᅩ -->
+ <item key="0x69" value="0x1163"/> <!-- i → ᅟᅣ -->
+ <item key="0x6a" value="0x1165"/> <!-- j → ᅟᅥ -->
+ <item key="0x6b" value="0x1161"/> <!-- k → ᅟᅡ -->
+ <item key="0x6c" value="0x1175"/> <!-- l → ᅟᅵ -->
+ <item key="0x6d" value="0x1173"/> <!-- m → ᅟᅳ -->
+ <item key="0x6e" value="0x116e"/> <!-- n → ᅟᅮ -->
+ <item key="0x6f" value="0x1162"/> <!-- o → ᅟᅢ -->
+ <item key="0x70" value="0x1166"/> <!-- p → ᅟᅦ -->
+ <item key="0x71" value="0x1107"/> <!-- q → ᄇᅠ -->
+ <item key="0x72" value="0x1100"/> <!-- r → ᄀᅠ -->
+ <item key="0x73" value="0x1102"/> <!-- s → ᄂᅠ -->
+ <item key="0x74" value="0x1109"/> <!-- t → ᄉᅠ -->
+ <item key="0x75" value="0x1167"/> <!-- u → ᅟᅧ -->
+ <item key="0x76" value="0x1111"/> <!-- v → ᄑᅠ -->
+ <item key="0x77" value="0x110c"/> <!-- w → ᄌᅠ -->
+ <item key="0x78" value="0x1110"/> <!-- x → ᄐᅠ -->
+ <item key="0x79" value="0x116d"/> <!-- y → ᅟᅭ -->
+ <item key="0x7a" value="0x110f"/> <!-- z → ᄏᅠ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x007e"/> <!-- ~ → ~ -->
+ </map>
+
+ <include file="hangul-combination-full.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-32.xml.template b/data/keyboards/hangul-keyboard-32.xml.template
new file mode 100644
index 0000000..5920069
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-32.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="32" type="jaso">
+
+ <_name>Sebeolsik Dubeol Layout</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x0021"/> <!-- ! → ! -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x0027"/> <!-- ' → ' -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x002f"/> <!-- / → / -->
+ <item key="0x30" value="0x0030"/> <!-- 0 → 0 -->
+ <item key="0x31" value="0x0031"/> <!-- 1 → 1 -->
+ <item key="0x32" value="0x0032"/> <!-- 2 → 2 -->
+ <item key="0x33" value="0x0033"/> <!-- 3 → 3 -->
+ <item key="0x34" value="0x0034"/> <!-- 4 → 4 -->
+ <item key="0x35" value="0x0035"/> <!-- 5 → 5 -->
+ <item key="0x36" value="0x0036"/> <!-- 6 → 6 -->
+ <item key="0x37" value="0x0037"/> <!-- 7 → 7 -->
+ <item key="0x38" value="0x0038"/> <!-- 8 → 8 -->
+ <item key="0x39" value="0x0039"/> <!-- 9 → 9 -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x003b"/> <!-- ; → ; -->
+ <item key="0x3c" value="0x003c"/> <!-- < → < -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x003e"/> <!-- > → > -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x11b7"/> <!-- A → ᅟᅠᆷ -->
+ <item key="0x42" value="0x1172"/> <!-- B → ᅟᅲ -->
+ <item key="0x43" value="0x11be"/> <!-- C → ᅟᅠᆾ -->
+ <item key="0x44" value="0x11bc"/> <!-- D → ᅟᅠᆼ -->
+ <item key="0x45" value="0x11ae"/> <!-- E → ᅟᅠᆮ -->
+ <item key="0x46" value="0x11af"/> <!-- F → ᅟᅠᆯ -->
+ <item key="0x47" value="0x11c2"/> <!-- G → ᅟᅠᇂ -->
+ <item key="0x48" value="0x1169"/> <!-- H → ᅟᅩ -->
+ <item key="0x49" value="0x1163"/> <!-- I → ᅟᅣ -->
+ <item key="0x4a" value="0x1165"/> <!-- J → ᅟᅥ -->
+ <item key="0x4b" value="0x1161"/> <!-- K → ᅟᅡ -->
+ <item key="0x4c" value="0x1175"/> <!-- L → ᅟᅵ -->
+ <item key="0x4d" value="0x1173"/> <!-- M → ᅟᅳ -->
+ <item key="0x4e" value="0x116e"/> <!-- N → ᅟᅮ -->
+ <item key="0x4f" value="0x1164"/> <!-- O → ᅟᅤ -->
+ <item key="0x50" value="0x1168"/> <!-- P → ᅟᅨ -->
+ <item key="0x51" value="0x11b8"/> <!-- Q → ᅟᅠᆸ -->
+ <item key="0x52" value="0x11a8"/> <!-- R → ᅟᅠᆨ -->
+ <item key="0x53" value="0x11ab"/> <!-- S → ᅟᅠᆫ -->
+ <item key="0x54" value="0x11ba"/> <!-- T → ᅟᅠᆺ -->
+ <item key="0x55" value="0x1167"/> <!-- U → ᅟᅧ -->
+ <item key="0x56" value="0x11c1"/> <!-- V → ᅟᅠᇁ -->
+ <item key="0x57" value="0x11bd"/> <!-- W → ᅟᅠᆽ -->
+ <item key="0x58" value="0x11c0"/> <!-- X → ᅟᅠᇀ -->
+ <item key="0x59" value="0x116d"/> <!-- Y → ᅟᅭ -->
+ <item key="0x5a" value="0x11bf"/> <!-- Z → ᅟᅠᆿ -->
+ <item key="0x5b" value="0x005b"/> <!-- [ → [ -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x005d"/> <!-- ] → ] -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x1106"/> <!-- a → ᄆᅠ -->
+ <item key="0x62" value="0x1172"/> <!-- b → ᅟᅲ -->
+ <item key="0x63" value="0x110e"/> <!-- c → ᄎᅠ -->
+ <item key="0x64" value="0x110b"/> <!-- d → ᄋᅠ -->
+ <item key="0x65" value="0x1103"/> <!-- e → ᄃᅠ -->
+ <item key="0x66" value="0x1105"/> <!-- f → ᄅᅠ -->
+ <item key="0x67" value="0x1112"/> <!-- g → ᄒᅠ -->
+ <item key="0x68" value="0x1169"/> <!-- h → ᅟᅩ -->
+ <item key="0x69" value="0x1163"/> <!-- i → ᅟᅣ -->
+ <item key="0x6a" value="0x1165"/> <!-- j → ᅟᅥ -->
+ <item key="0x6b" value="0x1161"/> <!-- k → ᅟᅡ -->
+ <item key="0x6c" value="0x1175"/> <!-- l → ᅟᅵ -->
+ <item key="0x6d" value="0x1173"/> <!-- m → ᅟᅳ -->
+ <item key="0x6e" value="0x116e"/> <!-- n → ᅟᅮ -->
+ <item key="0x6f" value="0x1162"/> <!-- o → ᅟᅢ -->
+ <item key="0x70" value="0x1166"/> <!-- p → ᅟᅦ -->
+ <item key="0x71" value="0x1107"/> <!-- q → ᄇᅠ -->
+ <item key="0x72" value="0x1100"/> <!-- r → ᄀᅠ -->
+ <item key="0x73" value="0x1102"/> <!-- s → ᄂᅠ -->
+ <item key="0x74" value="0x1109"/> <!-- t → ᄉᅠ -->
+ <item key="0x75" value="0x1167"/> <!-- u → ᅟᅧ -->
+ <item key="0x76" value="0x1111"/> <!-- v → ᄑᅠ -->
+ <item key="0x77" value="0x110c"/> <!-- w → ᄌᅠ -->
+ <item key="0x78" value="0x1110"/> <!-- x → ᄐᅠ -->
+ <item key="0x79" value="0x116d"/> <!-- y → ᅟᅭ -->
+ <item key="0x7a" value="0x110f"/> <!-- z → ᄏᅠ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x203b"/> <!-- ~ → ※ -->
+ </map>
+
+ <include file="hangul-combination-default.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-39.xml.template b/data/keyboards/hangul-keyboard-39.xml.template
new file mode 100644
index 0000000..78cfb50
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-39.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="39" type="jaso">
+
+ <_name>Sebeolsik 390</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x11bd"/> <!-- ! → ᅟᅠᆽ -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x1110"/> <!-- ' → ᄐᅠ -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x1169"/> <!-- / → ᅟᅩ -->
+ <item key="0x30" value="0x110f"/> <!-- 0 → ᄏᅠ -->
+ <item key="0x31" value="0x11c2"/> <!-- 1 → ᅟᅠᇂ -->
+ <item key="0x32" value="0x11bb"/> <!-- 2 → ᅟᅠᆻ -->
+ <item key="0x33" value="0x11b8"/> <!-- 3 → ᅟᅠᆸ -->
+ <item key="0x34" value="0x116d"/> <!-- 4 → ᅟᅭ -->
+ <item key="0x35" value="0x1172"/> <!-- 5 → ᅟᅲ -->
+ <item key="0x36" value="0x1163"/> <!-- 6 → ᅟᅣ -->
+ <item key="0x37" value="0x1168"/> <!-- 7 → ᅟᅨ -->
+ <item key="0x38" value="0x1174"/> <!-- 8 → ᅟᅴ -->
+ <item key="0x39" value="0x116e"/> <!-- 9 → ᅟᅮ -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x1107"/> <!-- ; → ᄇᅠ -->
+ <item key="0x3c" value="0x0032"/> <!-- < → 2 -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x0033"/> <!-- > → 3 -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x11ae"/> <!-- A → ᅟᅠᆮ -->
+ <item key="0x42" value="0x0021"/> <!-- B → ! -->
+ <item key="0x43" value="0x11b1"/> <!-- C → ᅟᅠᆱ -->
+ <item key="0x44" value="0x11b0"/> <!-- D → ᅟᅠᆰ -->
+ <item key="0x45" value="0x11bf"/> <!-- E → ᅟᅠᆿ -->
+ <item key="0x46" value="0x11a9"/> <!-- F → ᅟᅠᆩ -->
+ <item key="0x47" value="0x002f"/> <!-- G → / -->
+ <item key="0x48" value="0x0027"/> <!-- H → ' -->
+ <item key="0x49" value="0x0038"/> <!-- I → 8 -->
+ <item key="0x4a" value="0x0034"/> <!-- J → 4 -->
+ <item key="0x4b" value="0x0035"/> <!-- K → 5 -->
+ <item key="0x4c" value="0x0036"/> <!-- L → 6 -->
+ <item key="0x4d" value="0x0031"/> <!-- M → 1 -->
+ <item key="0x4e" value="0x0030"/> <!-- N → 0 -->
+ <item key="0x4f" value="0x0039"/> <!-- O → 9 -->
+ <item key="0x50" value="0x003e"/> <!-- P → > -->
+ <item key="0x51" value="0x11c1"/> <!-- Q → ᅟᅠᇁ -->
+ <item key="0x52" value="0x1164"/> <!-- R → ᅟᅤ -->
+ <item key="0x53" value="0x11ad"/> <!-- S → ᅟᅠᆭ -->
+ <item key="0x54" value="0x003b"/> <!-- T → ; -->
+ <item key="0x55" value="0x0037"/> <!-- U → 7 -->
+ <item key="0x56" value="0x11b6"/> <!-- V → ᅟᅠᆶ -->
+ <item key="0x57" value="0x11c0"/> <!-- W → ᅟᅠᇀ -->
+ <item key="0x58" value="0x11b9"/> <!-- X → ᅟᅠᆹ -->
+ <item key="0x59" value="0x003c"/> <!-- Y → < -->
+ <item key="0x5a" value="0x11be"/> <!-- Z → ᅟᅠᆾ -->
+ <item key="0x5b" value="0x005b"/> <!-- [ → [ -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x005d"/> <!-- ] → ] -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x11bc"/> <!-- a → ᅟᅠᆼ -->
+ <item key="0x62" value="0x116e"/> <!-- b → ᅟᅮ -->
+ <item key="0x63" value="0x1166"/> <!-- c → ᅟᅦ -->
+ <item key="0x64" value="0x1175"/> <!-- d → ᅟᅵ -->
+ <item key="0x65" value="0x1167"/> <!-- e → ᅟᅧ -->
+ <item key="0x66" value="0x1161"/> <!-- f → ᅟᅡ -->
+ <item key="0x67" value="0x1173"/> <!-- g → ᅟᅳ -->
+ <item key="0x68" value="0x1102"/> <!-- h → ᄂᅠ -->
+ <item key="0x69" value="0x1106"/> <!-- i → ᄆᅠ -->
+ <item key="0x6a" value="0x110b"/> <!-- j → ᄋᅠ -->
+ <item key="0x6b" value="0x1100"/> <!-- k → ᄀᅠ -->
+ <item key="0x6c" value="0x110c"/> <!-- l → ᄌᅠ -->
+ <item key="0x6d" value="0x1112"/> <!-- m → ᄒᅠ -->
+ <item key="0x6e" value="0x1109"/> <!-- n → ᄉᅠ -->
+ <item key="0x6f" value="0x110e"/> <!-- o → ᄎᅠ -->
+ <item key="0x70" value="0x1111"/> <!-- p → ᄑᅠ -->
+ <item key="0x71" value="0x11ba"/> <!-- q → ᅟᅠᆺ -->
+ <item key="0x72" value="0x1162"/> <!-- r → ᅟᅢ -->
+ <item key="0x73" value="0x11ab"/> <!-- s → ᅟᅠᆫ -->
+ <item key="0x74" value="0x1165"/> <!-- t → ᅟᅥ -->
+ <item key="0x75" value="0x1103"/> <!-- u → ᄃᅠ -->
+ <item key="0x76" value="0x1169"/> <!-- v → ᅟᅩ -->
+ <item key="0x77" value="0x11af"/> <!-- w → ᅟᅠᆯ -->
+ <item key="0x78" value="0x11a8"/> <!-- x → ᅟᅠᆨ -->
+ <item key="0x79" value="0x1105"/> <!-- y → ᄅᅠ -->
+ <item key="0x7a" value="0x11b7"/> <!-- z → ᅟᅠᆷ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x007e"/> <!-- ~ → ~ -->
+ </map>
+
+ <include file="hangul-combination-default.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-3f.xml.template b/data/keyboards/hangul-keyboard-3f.xml.template
new file mode 100644
index 0000000..c563df9
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-3f.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="3f" type="jaso">
+
+ <_name>Sebeolsik Final</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x11a9"/> <!-- ! → ᅟᅠᆩ -->
+ <item key="0x22" value="0x00b7"/> <!-- " → · -->
+ <item key="0x23" value="0x11bd"/> <!-- # → ᅟᅠᆽ -->
+ <item key="0x24" value="0x11b5"/> <!-- $ → ᅟᅠᆵ -->
+ <item key="0x25" value="0x11b4"/> <!-- % → ᅟᅠᆴ -->
+ <item key="0x26" value="0x201c"/> <!-- & → “ -->
+ <item key="0x27" value="0x1110"/> <!-- ' → ᄐᅠ -->
+ <item key="0x28" value="0x0027"/> <!-- ( → ' -->
+ <item key="0x29" value="0x007e"/> <!-- ) → ~ -->
+ <item key="0x2a" value="0x201d"/> <!-- * → ” -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x0029"/> <!-- - → ) -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x1169"/> <!-- / → ᅟᅩ -->
+ <item key="0x30" value="0x110f"/> <!-- 0 → ᄏᅠ -->
+ <item key="0x31" value="0x11c2"/> <!-- 1 → ᅟᅠᇂ -->
+ <item key="0x32" value="0x11bb"/> <!-- 2 → ᅟᅠᆻ -->
+ <item key="0x33" value="0x11b8"/> <!-- 3 → ᅟᅠᆸ -->
+ <item key="0x34" value="0x116d"/> <!-- 4 → ᅟᅭ -->
+ <item key="0x35" value="0x1172"/> <!-- 5 → ᅟᅲ -->
+ <item key="0x36" value="0x1163"/> <!-- 6 → ᅟᅣ -->
+ <item key="0x37" value="0x1168"/> <!-- 7 → ᅟᅨ -->
+ <item key="0x38" value="0x1174"/> <!-- 8 → ᅟᅴ -->
+ <item key="0x39" value="0x116e"/> <!-- 9 → ᅟᅮ -->
+ <item key="0x3a" value="0x0034"/> <!-- : → 4 -->
+ <item key="0x3b" value="0x1107"/> <!-- ; → ᄇᅠ -->
+ <item key="0x3c" value="0x002c"/> <!-- < → , -->
+ <item key="0x3d" value="0x003e"/> <!-- = → > -->
+ <item key="0x3e" value="0x002e"/> <!-- > → . -->
+ <item key="0x3f" value="0x0021"/> <!-- ? → ! -->
+ <item key="0x40" value="0x11b0"/> <!-- @ → ᅟᅠᆰ -->
+ <item key="0x41" value="0x11ae"/> <!-- A → ᅟᅠᆮ -->
+ <item key="0x42" value="0x003f"/> <!-- B → ? -->
+ <item key="0x43" value="0x11bf"/> <!-- C → ᅟᅠᆿ -->
+ <item key="0x44" value="0x11b2"/> <!-- D → ᅟᅠᆲ -->
+ <item key="0x45" value="0x11ac"/> <!-- E → ᅟᅠᆬ -->
+ <item key="0x46" value="0x11b1"/> <!-- F → ᅟᅠᆱ -->
+ <item key="0x47" value="0x1164"/> <!-- G → ᅟᅤ -->
+ <item key="0x48" value="0x0030"/> <!-- H → 0 -->
+ <item key="0x49" value="0x0037"/> <!-- I → 7 -->
+ <item key="0x4a" value="0x0031"/> <!-- J → 1 -->
+ <item key="0x4b" value="0x0032"/> <!-- K → 2 -->
+ <item key="0x4c" value="0x0033"/> <!-- L → 3 -->
+ <item key="0x4d" value="0x0022"/> <!-- M → " -->
+ <item key="0x4e" value="0x002d"/> <!-- N → - -->
+ <item key="0x4f" value="0x0038"/> <!-- O → 8 -->
+ <item key="0x50" value="0x0039"/> <!-- P → 9 -->
+ <item key="0x51" value="0x11c1"/> <!-- Q → ᅟᅠᇁ -->
+ <item key="0x52" value="0x11b6"/> <!-- R → ᅟᅠᆶ -->
+ <item key="0x53" value="0x11ad"/> <!-- S → ᅟᅠᆭ -->
+ <item key="0x54" value="0x11b3"/> <!-- T → ᅟᅠᆳ -->
+ <item key="0x55" value="0x0036"/> <!-- U → 6 -->
+ <item key="0x56" value="0x11aa"/> <!-- V → ᅟᅠᆪ -->
+ <item key="0x57" value="0x11c0"/> <!-- W → ᅟᅠᇀ -->
+ <item key="0x58" value="0x11b9"/> <!-- X → ᅟᅠᆹ -->
+ <item key="0x59" value="0x0035"/> <!-- Y → 5 -->
+ <item key="0x5a" value="0x11be"/> <!-- Z → ᅟᅠᆾ -->
+ <item key="0x5b" value="0x0028"/> <!-- [ → ( -->
+ <item key="0x5c" value="0x003a"/> <!-- \ → : -->
+ <item key="0x5d" value="0x003c"/> <!-- ] → < -->
+ <item key="0x5e" value="0x003d"/> <!-- ^ → = -->
+ <item key="0x5f" value="0x003b"/> <!-- _ → ; -->
+ <item key="0x60" value="0x002a"/> <!-- ` → * -->
+ <item key="0x61" value="0x11bc"/> <!-- a → ᅟᅠᆼ -->
+ <item key="0x62" value="0x116e"/> <!-- b → ᅟᅮ -->
+ <item key="0x63" value="0x1166"/> <!-- c → ᅟᅦ -->
+ <item key="0x64" value="0x1175"/> <!-- d → ᅟᅵ -->
+ <item key="0x65" value="0x1167"/> <!-- e → ᅟᅧ -->
+ <item key="0x66" value="0x1161"/> <!-- f → ᅟᅡ -->
+ <item key="0x67" value="0x1173"/> <!-- g → ᅟᅳ -->
+ <item key="0x68" value="0x1102"/> <!-- h → ᄂᅠ -->
+ <item key="0x69" value="0x1106"/> <!-- i → ᄆᅠ -->
+ <item key="0x6a" value="0x110b"/> <!-- j → ᄋᅠ -->
+ <item key="0x6b" value="0x1100"/> <!-- k → ᄀᅠ -->
+ <item key="0x6c" value="0x110c"/> <!-- l → ᄌᅠ -->
+ <item key="0x6d" value="0x1112"/> <!-- m → ᄒᅠ -->
+ <item key="0x6e" value="0x1109"/> <!-- n → ᄉᅠ -->
+ <item key="0x6f" value="0x110e"/> <!-- o → ᄎᅠ -->
+ <item key="0x70" value="0x1111"/> <!-- p → ᄑᅠ -->
+ <item key="0x71" value="0x11ba"/> <!-- q → ᅟᅠᆺ -->
+ <item key="0x72" value="0x1162"/> <!-- r → ᅟᅢ -->
+ <item key="0x73" value="0x11ab"/> <!-- s → ᅟᅠᆫ -->
+ <item key="0x74" value="0x1165"/> <!-- t → ᅟᅥ -->
+ <item key="0x75" value="0x1103"/> <!-- u → ᄃᅠ -->
+ <item key="0x76" value="0x1169"/> <!-- v → ᅟᅩ -->
+ <item key="0x77" value="0x11af"/> <!-- w → ᅟᅠᆯ -->
+ <item key="0x78" value="0x11a8"/> <!-- x → ᅟᅠᆨ -->
+ <item key="0x79" value="0x1105"/> <!-- y → ᄅᅠ -->
+ <item key="0x7a" value="0x11b7"/> <!-- z → ᅟᅠᆷ -->
+ <item key="0x7b" value="0x0025"/> <!-- { → % -->
+ <item key="0x7c" value="0x005c"/> <!-- | → \ -->
+ <item key="0x7d" value="0x002f"/> <!-- } → / -->
+ <item key="0x7e" value="0x203b"/> <!-- ~ → ※ -->
+ </map>
+
+ <include file="hangul-combination-default.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-3s.xml.template b/data/keyboards/hangul-keyboard-3s.xml.template
new file mode 100644
index 0000000..5a95490
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-3s.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="3s" type="jaso">
+
+ <_name>Sebeolsik Noshift</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x0021"/> <!-- ! → ! -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x1110"/> <!-- ' → ᄐᅠ -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x11bd"/> <!-- - → ᅟᅠᆽ -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x11ae"/> <!-- / → ᅟᅠᆮ -->
+ <item key="0x30" value="0x1164"/> <!-- 0 → ᅟᅤ -->
+ <item key="0x31" value="0x11c2"/> <!-- 1 → ᅟᅠᇂ -->
+ <item key="0x32" value="0x11bb"/> <!-- 2 → ᅟᅠᆻ -->
+ <item key="0x33" value="0x11b8"/> <!-- 3 → ᅟᅠᆸ -->
+ <item key="0x34" value="0x116d"/> <!-- 4 → ᅟᅭ -->
+ <item key="0x35" value="0x1172"/> <!-- 5 → ᅟᅲ -->
+ <item key="0x36" value="0x1163"/> <!-- 6 → ᅟᅣ -->
+ <item key="0x37" value="0x1168"/> <!-- 7 → ᅟᅨ -->
+ <item key="0x38" value="0x1174"/> <!-- 8 → ᅟᅴ -->
+ <item key="0x39" value="0x110f"/> <!-- 9 → ᄏᅠ -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x1107"/> <!-- ; → ᄇᅠ -->
+ <item key="0x3c" value="0x0032"/> <!-- < → 2 -->
+ <item key="0x3d" value="0x11be"/> <!-- = → ᅟᅠᆾ -->
+ <item key="0x3e" value="0x0033"/> <!-- > → 3 -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x11bc"/> <!-- A → ᅟᅠᆼ -->
+ <item key="0x42" value="0x0021"/> <!-- B → ! -->
+ <item key="0x43" value="0x005c"/> <!-- C → \ -->
+ <item key="0x44" value="0x005d"/> <!-- D → ] -->
+ <item key="0x45" value="0x1167"/> <!-- E → ᅟᅧ -->
+ <item key="0x46" value="0x1161"/> <!-- F → ᅟᅡ -->
+ <item key="0x47" value="0x002f"/> <!-- G → / -->
+ <item key="0x48" value="0x0027"/> <!-- H → ' -->
+ <item key="0x49" value="0x0038"/> <!-- I → 8 -->
+ <item key="0x4a" value="0x0034"/> <!-- J → 4 -->
+ <item key="0x4b" value="0x0035"/> <!-- K → 5 -->
+ <item key="0x4c" value="0x0036"/> <!-- L → 6 -->
+ <item key="0x4d" value="0x0031"/> <!-- M → 1 -->
+ <item key="0x4e" value="0x0030"/> <!-- N → 0 -->
+ <item key="0x4f" value="0x0039"/> <!-- O → 9 -->
+ <item key="0x50" value="0x003e"/> <!-- P → > -->
+ <item key="0x51" value="0x11ba"/> <!-- Q → ᅟᅠᆺ -->
+ <item key="0x52" value="0x1162"/> <!-- R → ᅟᅢ -->
+ <item key="0x53" value="0x005b"/> <!-- S → [ -->
+ <item key="0x54" value="0x003b"/> <!-- T → ; -->
+ <item key="0x55" value="0x0037"/> <!-- U → 7 -->
+ <item key="0x56" value="0x1169"/> <!-- V → ᅟᅩ -->
+ <item key="0x57" value="0x11af"/> <!-- W → ᅟᅠᆯ -->
+ <item key="0x58" value="0x003d"/> <!-- X → = -->
+ <item key="0x59" value="0x003c"/> <!-- Y → < -->
+ <item key="0x5a" value="0x002d"/> <!-- Z → - -->
+ <item key="0x5b" value="0x11c0"/> <!-- [ → ᅟᅠᇀ -->
+ <item key="0x5c" value="0x11bf"/> <!-- \ → ᅟᅠᆿ -->
+ <item key="0x5d" value="0x11c1"/> <!-- ] → ᅟᅠᇁ -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x11bc"/> <!-- a → ᅟᅠᆼ -->
+ <item key="0x62" value="0x116e"/> <!-- b → ᅟᅮ -->
+ <item key="0x63" value="0x1166"/> <!-- c → ᅟᅦ -->
+ <item key="0x64" value="0x1175"/> <!-- d → ᅟᅵ -->
+ <item key="0x65" value="0x1167"/> <!-- e → ᅟᅧ -->
+ <item key="0x66" value="0x1161"/> <!-- f → ᅟᅡ -->
+ <item key="0x67" value="0x1173"/> <!-- g → ᅟᅳ -->
+ <item key="0x68" value="0x1102"/> <!-- h → ᄂᅠ -->
+ <item key="0x69" value="0x1106"/> <!-- i → ᄆᅠ -->
+ <item key="0x6a" value="0x110b"/> <!-- j → ᄋᅠ -->
+ <item key="0x6b" value="0x1100"/> <!-- k → ᄀᅠ -->
+ <item key="0x6c" value="0x110c"/> <!-- l → ᄌᅠ -->
+ <item key="0x6d" value="0x1112"/> <!-- m → ᄒᅠ -->
+ <item key="0x6e" value="0x1109"/> <!-- n → ᄉᅠ -->
+ <item key="0x6f" value="0x110e"/> <!-- o → ᄎᅠ -->
+ <item key="0x70" value="0x1111"/> <!-- p → ᄑᅠ -->
+ <item key="0x71" value="0x11ba"/> <!-- q → ᅟᅠᆺ -->
+ <item key="0x72" value="0x1162"/> <!-- r → ᅟᅢ -->
+ <item key="0x73" value="0x11ab"/> <!-- s → ᅟᅠᆫ -->
+ <item key="0x74" value="0x1165"/> <!-- t → ᅟᅥ -->
+ <item key="0x75" value="0x1103"/> <!-- u → ᄃᅠ -->
+ <item key="0x76" value="0x1169"/> <!-- v → ᅟᅩ -->
+ <item key="0x77" value="0x11af"/> <!-- w → ᅟᅠᆯ -->
+ <item key="0x78" value="0x11a8"/> <!-- x → ᅟᅠᆨ -->
+ <item key="0x79" value="0x1105"/> <!-- y → ᄅᅠ -->
+ <item key="0x7a" value="0x11b7"/> <!-- z → ᅟᅠᆷ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x007e"/> <!-- ~ → ~ -->
+ </map>
+
+ <include file="hangul-combination-default.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-3y.xml.template b/data/keyboards/hangul-keyboard-3y.xml.template
new file mode 100644
index 0000000..67f0ae9
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-3y.xml.template
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="3y" type="jaso-yet">
+
+ <_name>Sebeolsik Yetgeul</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x11bd"/> <!-- ! → ᅟᅠᆽ -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x1110"/> <!-- ' → ᄐᅠ -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x1169"/> <!-- / → ᅟᅩ -->
+ <item key="0x30" value="0x110f"/> <!-- 0 → ᄏᅠ -->
+ <item key="0x31" value="0x11c2"/> <!-- 1 → ᅟᅠᇂ -->
+ <item key="0x32" value="0x11bb"/> <!-- 2 → ᅟᅠᆻ -->
+ <item key="0x33" value="0x11b8"/> <!-- 3 → ᅟᅠᆸ -->
+ <item key="0x34" value="0x116d"/> <!-- 4 → ᅟᅭ -->
+ <item key="0x35" value="0x1172"/> <!-- 5 → ᅟᅲ -->
+ <item key="0x36" value="0x1163"/> <!-- 6 → ᅟᅣ -->
+ <item key="0x37" value="0x1168"/> <!-- 7 → ᅟᅨ -->
+ <item key="0x38" value="0x1174"/> <!-- 8 → ᅟᅴ -->
+ <item key="0x39" value="0x116e"/> <!-- 9 → ᅟᅮ -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x1107"/> <!-- ; → ᄇᅠ -->
+ <item key="0x3c" value="0x113c"/> <!-- < → ᄼᅠ -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x113e"/> <!-- > → ᄾᅠ -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x11eb"/> <!-- @ → ᅟᅠᇫ -->
+ <item key="0x41" value="0x11ae"/> <!-- A → ᅟᅠᆮ -->
+ <item key="0x42" value="0x0021"/> <!-- B → ! -->
+ <item key="0x43" value="0x11b1"/> <!-- C → ᅟᅠᆱ -->
+ <item key="0x44" value="0x11b0"/> <!-- D → ᅟᅠᆰ -->
+ <item key="0x45" value="0x11bf"/> <!-- E → ᅟᅠᆿ -->
+ <item key="0x46" value="0x11a9"/> <!-- F → ᅟᅠᆩ -->
+ <item key="0x47" value="0x119e"/> <!-- G → ᅟᆞ -->
+ <item key="0x48" value="0x0027"/> <!-- H → ' -->
+ <item key="0x49" value="0x1154"/> <!-- I → ᅔᅠ -->
+ <item key="0x4a" value="0x114c"/> <!-- J → ᅌᅠ -->
+ <item key="0x4b" value="0x114e"/> <!-- K → ᅎᅠ -->
+ <item key="0x4c" value="0x1150"/> <!-- L → ᅐᅠ -->
+ <item key="0x4d" value="0x1159"/> <!-- M → ᅙᅠ -->
+ <item key="0x4e" value="0x1140"/> <!-- N → ᅀᅠ -->
+ <item key="0x4f" value="0x1155"/> <!-- O → ᅕᅠ -->
+ <item key="0x50" value="0x003e"/> <!-- P → > -->
+ <item key="0x51" value="0x11c1"/> <!-- Q → ᅟᅠᇁ -->
+ <item key="0x52" value="0x1164"/> <!-- R → ᅟᅤ -->
+ <item key="0x53" value="0x11ad"/> <!-- S → ᅟᅠᆭ -->
+ <item key="0x54" value="0x003b"/> <!-- T → ; -->
+ <item key="0x55" value="0x00b7"/> <!-- U → · -->
+ <item key="0x56" value="0x11b6"/> <!-- V → ᅟᅠᆶ -->
+ <item key="0x57" value="0x11c0"/> <!-- W → ᅟᅠᇀ -->
+ <item key="0x58" value="0x11b9"/> <!-- X → ᅟᅠᆹ -->
+ <item key="0x59" value="0x003c"/> <!-- Y → < -->
+ <item key="0x5a" value="0x11be"/> <!-- Z → ᅟᅠᆾ -->
+ <item key="0x5b" value="0x005b"/> <!-- [ → [ -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x005d"/> <!-- ] → ] -->
+ <item key="0x5e" value="0x114c"/> <!-- ^ → ᅌᅠ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x11f9"/> <!-- ` → ᅟᅠᇹ -->
+ <item key="0x61" value="0x11bc"/> <!-- a → ᅟᅠᆼ -->
+ <item key="0x62" value="0x116e"/> <!-- b → ᅟᅮ -->
+ <item key="0x63" value="0x1166"/> <!-- c → ᅟᅦ -->
+ <item key="0x64" value="0x1175"/> <!-- d → ᅟᅵ -->
+ <item key="0x65" value="0x1167"/> <!-- e → ᅟᅧ -->
+ <item key="0x66" value="0x1161"/> <!-- f → ᅟᅡ -->
+ <item key="0x67" value="0x1173"/> <!-- g → ᅟᅳ -->
+ <item key="0x68" value="0x1102"/> <!-- h → ᄂᅠ -->
+ <item key="0x69" value="0x1106"/> <!-- i → ᄆᅠ -->
+ <item key="0x6a" value="0x110b"/> <!-- j → ᄋᅠ -->
+ <item key="0x6b" value="0x1100"/> <!-- k → ᄀᅠ -->
+ <item key="0x6c" value="0x110c"/> <!-- l → ᄌᅠ -->
+ <item key="0x6d" value="0x1112"/> <!-- m → ᄒᅠ -->
+ <item key="0x6e" value="0x1109"/> <!-- n → ᄉᅠ -->
+ <item key="0x6f" value="0x110e"/> <!-- o → ᄎᅠ -->
+ <item key="0x70" value="0x1111"/> <!-- p → ᄑᅠ -->
+ <item key="0x71" value="0x11ba"/> <!-- q → ᅟᅠᆺ -->
+ <item key="0x72" value="0x1162"/> <!-- r → ᅟᅢ -->
+ <item key="0x73" value="0x11ab"/> <!-- s → ᅟᅠᆫ -->
+ <item key="0x74" value="0x1165"/> <!-- t → ᅟᅥ -->
+ <item key="0x75" value="0x1103"/> <!-- u → ᄃᅠ -->
+ <item key="0x76" value="0x1169"/> <!-- v → ᅟᅩ -->
+ <item key="0x77" value="0x11af"/> <!-- w → ᅟᅠᆯ -->
+ <item key="0x78" value="0x11a8"/> <!-- x → ᅟᅠᆨ -->
+ <item key="0x79" value="0x1105"/> <!-- y → ᄅᅠ -->
+ <item key="0x7a" value="0x11b7"/> <!-- z → ᅟᅠᆷ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x11f0"/> <!-- ~ → ᅟᅠᇰ -->
+ </map>
+
+ <include file="hangul-combination-full.xml"/>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-ahn.xml.template b/data/keyboards/hangul-keyboard-ahn.xml.template
new file mode 100644
index 0000000..0fa4d3c
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-ahn.xml.template
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="ahn" type="jaso">
+
+ <_name>Ahnmatae</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x0021"/> <!-- ! → ! -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x002e"/> <!-- ' → . -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x11b7"/> <!-- , → ᅟᅠᆷ -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x11af"/> <!-- . → ᅟᅠᆯ -->
+ <item key="0x2f" value="0x11c2"/> <!-- / → ᅟᅠᇂ -->
+ <item key="0x30" value="0x0030"/> <!-- 0 → 0 -->
+ <item key="0x31" value="0x0031"/> <!-- 1 → 1 -->
+ <item key="0x32" value="0x0032"/> <!-- 2 → 2 -->
+ <item key="0x33" value="0x0033"/> <!-- 3 → 3 -->
+ <item key="0x34" value="0x0034"/> <!-- 4 → 4 -->
+ <item key="0x35" value="0x0035"/> <!-- 5 → 5 -->
+ <item key="0x36" value="0x0036"/> <!-- 6 → 6 -->
+ <item key="0x37" value="0x0037"/> <!-- 7 → 7 -->
+ <item key="0x38" value="0x0038"/> <!-- 8 → 8 -->
+ <item key="0x39" value="0x0039"/> <!-- 9 → 9 -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x116e"/> <!-- ; → ᅟᅮ -->
+ <item key="0x3c" value="0x003c"/> <!-- < → < -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x003e"/> <!-- > → > -->
+ <item key="0x3f" value="0x11f9"/> <!-- ? → ᅟᅠᇹ -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x1107"/> <!-- A → ᄇᅠ -->
+ <item key="0x42" value="0x11f0"/> <!-- B → ᅟᅠᇰ -->
+ <item key="0x43" value="0x11b8"/> <!-- C → ᅟᅠᆸ -->
+ <item key="0x44" value="0x1103"/> <!-- D → ᄃᅠ -->
+ <item key="0x45" value="0x1102"/> <!-- E → ᄂᅠ -->
+ <item key="0x46" value="0x1100"/> <!-- F → ᄀᅠ -->
+ <item key="0x47" value="0x114c"/> <!-- G → ᅌᅠ -->
+ <item key="0x48" value="0x1165"/> <!-- H → ᅟᅥ -->
+ <item key="0x49" value="0x002f"/> <!-- I → / -->
+ <item key="0x4a" value="0x119e"/> <!-- J → ᅟᆞ -->
+ <item key="0x4b" value="0x1175"/> <!-- K → ᅟᅵ -->
+ <item key="0x4c" value="0x1169"/> <!-- L → ᅟᅩ -->
+ <item key="0x4d" value="0x11ab"/> <!-- M → ᅟᅠᆫ -->
+ <item key="0x4e" value="0x11eb"/> <!-- N → ᅟᅠᇫ -->
+ <item key="0x4f" value="0x005b"/> <!-- O → [ -->
+ <item key="0x50" value="0x005d"/> <!-- P → ] -->
+ <item key="0x51" value="0x1106"/> <!-- Q → ᄆᅠ -->
+ <item key="0x52" value="0x1105"/> <!-- R → ᄅᅠ -->
+ <item key="0x53" value="0x110c"/> <!-- S → ᄌᅠ -->
+ <item key="0x54" value="0x1159"/> <!-- T → ᅙᅠ -->
+ <item key="0x55" value="0x0027"/> <!-- U → ' -->
+ <item key="0x56" value="0x11a8"/> <!-- V → ᅟᅠᆨ -->
+ <item key="0x57" value="0x1140"/> <!-- W → ᅀᅠ -->
+ <item key="0x58" value="0x11ae"/> <!-- X → ᅟᅠᆮ -->
+ <item key="0x59" value="0x003b"/> <!-- Y → ; -->
+ <item key="0x5a" value="0x11bd"/> <!-- Z → ᅟᅠᆽ -->
+ <item key="0x5b" value="0x002c"/> <!-- [ → , -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x003f"/> <!-- ] → ? -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x1107"/> <!-- a → ᄇᅠ -->
+ <item key="0x62" value="0x11bc"/> <!-- b → ᅟᅠᆼ -->
+ <item key="0x63" value="0x11b8"/> <!-- c → ᅟᅠᆸ -->
+ <item key="0x64" value="0x1103"/> <!-- d → ᄃᅠ -->
+ <item key="0x65" value="0x1102"/> <!-- e → ᄂᅠ -->
+ <item key="0x66" value="0x1100"/> <!-- f → ᄀᅠ -->
+ <item key="0x67" value="0x110b"/> <!-- g → ᄋᅠ -->
+ <item key="0x68" value="0x1165"/> <!-- h → ᅟᅥ -->
+ <item key="0x69" value="0x1173"/> <!-- i → ᅟᅳ -->
+ <item key="0x6a" value="0x1161"/> <!-- j → ᅟᅡ -->
+ <item key="0x6b" value="0x1175"/> <!-- k → ᅟᅵ -->
+ <item key="0x6c" value="0x1169"/> <!-- l → ᅟᅩ -->
+ <item key="0x6d" value="0x11ab"/> <!-- m → ᅟᅠᆫ -->
+ <item key="0x6e" value="0x11ba"/> <!-- n → ᅟᅠᆺ -->
+ <item key="0x6f" value="0x116d"/> <!-- o → ᅟᅭ -->
+ <item key="0x70" value="0x1172"/> <!-- p → ᅟᅲ -->
+ <item key="0x71" value="0x1106"/> <!-- q → ᄆᅠ -->
+ <item key="0x72" value="0x1105"/> <!-- r → ᄅᅠ -->
+ <item key="0x73" value="0x110c"/> <!-- s → ᄌᅠ -->
+ <item key="0x74" value="0x1112"/> <!-- t → ᄒᅠ -->
+ <item key="0x75" value="0x1163"/> <!-- u → ᅟᅣ -->
+ <item key="0x76" value="0x11a8"/> <!-- v → ᅟᅠᆨ -->
+ <item key="0x77" value="0x1109"/> <!-- w → ᄉᅠ -->
+ <item key="0x78" value="0x11ae"/> <!-- x → ᅟᅠᆮ -->
+ <item key="0x79" value="0x1167"/> <!-- y → ᅟᅧ -->
+ <item key="0x7a" value="0x11bd"/> <!-- z → ᅟᅠᆽ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x007e"/> <!-- ~ → ~ -->
+ </map>
+
+ <combination id="0">
+ <item first="0x1100" second="0x1103" result="0x1104"/> <!-- ᄀ + ᄃ → ᄄ -->
+ <item first="0x1100" second="0x110b" result="0x1101"/> <!-- ᄀ + ᄋ → ᄁ -->
+ <item first="0x1100" second="0x1112" result="0x110f"/> <!-- ᄀ + ᄒ → ᄏ -->
+ <item first="0x1102" second="0x1109" result="0x110a"/> <!-- ᄂ + ᄉ → ᄊ -->
+ <item first="0x1103" second="0x1100" result="0x1104"/> <!-- ᄃ + ᄀ → ᄄ -->
+ <item first="0x1103" second="0x110c" result="0x110d"/> <!-- ᄃ + ᄌ → ᄍ -->
+ <item first="0x1103" second="0x1112" result="0x1110"/> <!-- ᄃ + ᄒ → ᄐ -->
+ <item first="0x1107" second="0x110c" result="0x1108"/> <!-- ᄇ + ᄌ → ᄈ -->
+ <item first="0x1107" second="0x1112" result="0x1111"/> <!-- ᄇ + ᄒ → ᄑ -->
+ <item first="0x1109" second="0x1102" result="0x110a"/> <!-- ᄉ + ᄂ → ᄊ -->
+ <item first="0x110b" second="0x1100" result="0x1101"/> <!-- ᄋ + ᄀ → ᄁ -->
+ <item first="0x110c" second="0x1103" result="0x110d"/> <!-- ᄌ + ᄃ → ᄍ -->
+ <item first="0x110c" second="0x1107" result="0x1108"/> <!-- ᄌ + ᄇ → ᄈ -->
+ <item first="0x110c" second="0x1112" result="0x110e"/> <!-- ᄌ + ᄒ → ᄎ -->
+ <item first="0x1112" second="0x1100" result="0x110f"/> <!-- ᄒ + ᄀ → ᄏ -->
+ <item first="0x1112" second="0x1103" result="0x1110"/> <!-- ᄒ + ᄃ → ᄐ -->
+ <item first="0x1112" second="0x1107" result="0x1111"/> <!-- ᄒ + ᄇ → ᄑ -->
+ <item first="0x1112" second="0x110c" result="0x110e"/> <!-- ᄒ + ᄌ → ᄎ -->
+ <item first="0x1161" second="0x1169" result="0x116a"/> <!-- ᅡ + ᅩ → ᅪ -->
+ <item first="0x1161" second="0x1175" result="0x1162"/> <!-- ᅡ + ᅵ → ᅢ -->
+ <item first="0x1162" second="0x1169" result="0x116b"/> <!-- ᅢ + ᅩ → ᅫ -->
+ <item first="0x1163" second="0x1175" result="0x1164"/> <!-- ᅣ + ᅵ → ᅤ -->
+ <item first="0x1165" second="0x116e" result="0x116f"/> <!-- ᅥ + ᅮ → ᅯ -->
+ <item first="0x1165" second="0x1175" result="0x1166"/> <!-- ᅥ + ᅵ → ᅦ -->
+ <item first="0x1166" second="0x116e" result="0x1170"/> <!-- ᅦ + ᅮ → ᅰ -->
+ <item first="0x1167" second="0x1175" result="0x1168"/> <!-- ᅧ + ᅵ → ᅨ -->
+ <item first="0x1169" second="0x1161" result="0x116a"/> <!-- ᅩ + ᅡ → ᅪ -->
+ <item first="0x1169" second="0x1175" result="0x116c"/> <!-- ᅩ + ᅵ → ᅬ -->
+ <item first="0x116a" second="0x1175" result="0x116b"/> <!-- ᅪ + ᅵ → ᅫ -->
+ <item first="0x116c" second="0x1161" result="0x116b"/> <!-- ᅬ + ᅡ → ᅫ -->
+ <item first="0x116e" second="0x1165" result="0x116f"/> <!-- ᅮ + ᅥ → ᅯ -->
+ <item first="0x116e" second="0x1175" result="0x1171"/> <!-- ᅮ + ᅵ → ᅱ -->
+ <item first="0x116f" second="0x1175" result="0x1170"/> <!-- ᅯ + ᅵ → ᅰ -->
+ <item first="0x1171" second="0x1165" result="0x1170"/> <!-- ᅱ + ᅥ → ᅰ -->
+ <item first="0x1173" second="0x1175" result="0x1174"/> <!-- ᅳ + ᅵ → ᅴ -->
+ <item first="0x1175" second="0x1161" result="0x1162"/> <!-- ᅵ + ᅡ → ᅢ -->
+ <item first="0x1175" second="0x1163" result="0x1164"/> <!-- ᅵ + ᅣ → ᅤ -->
+ <item first="0x1175" second="0x1165" result="0x1166"/> <!-- ᅵ + ᅥ → ᅦ -->
+ <item first="0x1175" second="0x1167" result="0x1168"/> <!-- ᅵ + ᅧ → ᅨ -->
+ <item first="0x1175" second="0x1169" result="0x116c"/> <!-- ᅵ + ᅩ → ᅬ -->
+ <item first="0x1175" second="0x116e" result="0x1171"/> <!-- ᅵ + ᅮ → ᅱ -->
+ <item first="0x1175" second="0x1173" result="0x1174"/> <!-- ᅵ + ᅳ → ᅴ -->
+ <item first="0x11a8" second="0x11af" result="0x11b0"/> <!-- ᆨ + ᆯ → ᆰ -->
+ <item first="0x11a8" second="0x11ba" result="0x11aa"/> <!-- ᆨ + ᆺ → ᆪ -->
+ <item first="0x11a8" second="0x11bc" result="0x11a9"/> <!-- ᆨ + ᆼ → ᆩ -->
+ <item first="0x11a8" second="0x11c2" result="0x11bf"/> <!-- ᆨ + ᇂ → ᆿ -->
+ <item first="0x11ab" second="0x11ba" result="0x11bb"/> <!-- ᆫ + ᆺ → ᆻ -->
+ <item first="0x11ab" second="0x11bd" result="0x11ac"/> <!-- ᆫ + ᆽ → ᆬ -->
+ <item first="0x11ab" second="0x11c2" result="0x11ad"/> <!-- ᆫ + ᇂ → ᆭ -->
+ <item first="0x11ae" second="0x11af" result="0x11ce"/> <!-- ᆮ + ᆯ → ᇎ -->
+ <item first="0x11ae" second="0x11c2" result="0x11c0"/> <!-- ᆮ + ᇂ → ᇀ -->
+ <item first="0x11af" second="0x11a8" result="0x11b0"/> <!-- ᆯ + ᆨ → ᆰ -->
+ <item first="0x11af" second="0x11ae" result="0x11ce"/> <!-- ᆯ + ᆮ → ᇎ -->
+ <item first="0x11af" second="0x11b7" result="0x11b1"/> <!-- ᆯ + ᆷ → ᆱ -->
+ <item first="0x11af" second="0x11b8" result="0x11b2"/> <!-- ᆯ + ᆸ → ᆲ -->
+ <item first="0x11af" second="0x11ba" result="0x11b3"/> <!-- ᆯ + ᆺ → ᆳ -->
+ <item first="0x11af" second="0x11c2" result="0x11b6"/> <!-- ᆯ + ᇂ → ᆶ -->
+ <item first="0x11b2" second="0x11c2" result="0x11b5"/> <!-- ᆲ + ᇂ → ᆵ -->
+ <item first="0x11b6" second="0x11ae" result="0x11b4"/> <!-- ᆶ + ᆮ → ᆴ -->
+ <item first="0x11b6" second="0x11b8" result="0x11b5"/> <!-- ᆶ + ᆸ → ᆵ -->
+ <item first="0x11b7" second="0x11af" result="0x11b1"/> <!-- ᆷ + ᆯ → ᆱ -->
+ <item first="0x11b8" second="0x11af" result="0x11b2"/> <!-- ᆸ + ᆯ → ᆲ -->
+ <item first="0x11b8" second="0x11ba" result="0x11b9"/> <!-- ᆸ + ᆺ → ᆹ -->
+ <item first="0x11b8" second="0x11c2" result="0x11c1"/> <!-- ᆸ + ᇂ → ᇁ -->
+ <item first="0x11ba" second="0x11a8" result="0x11aa"/> <!-- ᆺ + ᆨ → ᆪ -->
+ <item first="0x11ba" second="0x11ab" result="0x11bb"/> <!-- ᆺ + ᆫ → ᆻ -->
+ <item first="0x11ba" second="0x11af" result="0x11b3"/> <!-- ᆺ + ᆯ → ᆳ -->
+ <item first="0x11ba" second="0x11b8" result="0x11b9"/> <!-- ᆺ + ᆸ → ᆹ -->
+ <item first="0x11bc" second="0x11a8" result="0x11a9"/> <!-- ᆼ + ᆨ → ᆩ -->
+ <item first="0x11bd" second="0x11ab" result="0x11ac"/> <!-- ᆽ + ᆫ → ᆬ -->
+ <item first="0x11bd" second="0x11c2" result="0x11be"/> <!-- ᆽ + ᇂ → ᆾ -->
+ <item first="0x11c0" second="0x11af" result="0x11b4"/> <!-- ᇀ + ᆯ → ᆴ -->
+ <item first="0x11c1" second="0x11af" result="0x11b5"/> <!-- ᇁ + ᆯ → ᆵ -->
+ <item first="0x11c2" second="0x11a8" result="0x11bf"/> <!-- ᇂ + ᆨ → ᆿ -->
+ <item first="0x11c2" second="0x11ab" result="0x11ad"/> <!-- ᇂ + ᆫ → ᆭ -->
+ <item first="0x11c2" second="0x11ae" result="0x11c0"/> <!-- ᇂ + ᆮ → ᇀ -->
+ <item first="0x11c2" second="0x11af" result="0x11b6"/> <!-- ᇂ + ᆯ → ᆶ -->
+ <item first="0x11c2" second="0x11b8" result="0x11c1"/> <!-- ᇂ + ᆸ → ᇁ -->
+ <item first="0x11c2" second="0x11bd" result="0x11be"/> <!-- ᇂ + ᆽ → ᆾ -->
+ <item first="0x11ce" second="0x11c2" result="0x11b4"/> <!-- ᇎ + ᇂ → ᆴ -->
+ </combination>
+
+</hangul-keyboard>
diff --git a/data/keyboards/hangul-keyboard-ro.xml.template b/data/keyboards/hangul-keyboard-ro.xml.template
new file mode 100644
index 0000000..0f40813
--- /dev/null
+++ b/data/keyboards/hangul-keyboard-ro.xml.template
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<hangul-keyboard id="ro" type="romaja">
+
+ <_name>Romaja</_name>
+
+ <map id="0">
+ <item key="0x21" value="0x0021"/> <!-- ! → ! -->
+ <item key="0x22" value="0x0022"/> <!-- " → " -->
+ <item key="0x23" value="0x0023"/> <!-- # → # -->
+ <item key="0x24" value="0x0024"/> <!-- $ → $ -->
+ <item key="0x25" value="0x0025"/> <!-- % → % -->
+ <item key="0x26" value="0x0026"/> <!-- & → & -->
+ <item key="0x27" value="0x0027"/> <!-- ' → ' -->
+ <item key="0x28" value="0x0028"/> <!-- ( → ( -->
+ <item key="0x29" value="0x0029"/> <!-- ) → ) -->
+ <item key="0x2a" value="0x002a"/> <!-- * → * -->
+ <item key="0x2b" value="0x002b"/> <!-- + → + -->
+ <item key="0x2c" value="0x002c"/> <!-- , → , -->
+ <item key="0x2d" value="0x002d"/> <!-- - → - -->
+ <item key="0x2e" value="0x002e"/> <!-- . → . -->
+ <item key="0x2f" value="0x002f"/> <!-- / → / -->
+ <item key="0x30" value="0x0030"/> <!-- 0 → 0 -->
+ <item key="0x31" value="0x0031"/> <!-- 1 → 1 -->
+ <item key="0x32" value="0x0032"/> <!-- 2 → 2 -->
+ <item key="0x33" value="0x0033"/> <!-- 3 → 3 -->
+ <item key="0x34" value="0x0034"/> <!-- 4 → 4 -->
+ <item key="0x35" value="0x0035"/> <!-- 5 → 5 -->
+ <item key="0x36" value="0x0036"/> <!-- 6 → 6 -->
+ <item key="0x37" value="0x0037"/> <!-- 7 → 7 -->
+ <item key="0x38" value="0x0038"/> <!-- 8 → 8 -->
+ <item key="0x39" value="0x0039"/> <!-- 9 → 9 -->
+ <item key="0x3a" value="0x003a"/> <!-- : → : -->
+ <item key="0x3b" value="0x003b"/> <!-- ; → ; -->
+ <item key="0x3c" value="0x003c"/> <!-- < → < -->
+ <item key="0x3d" value="0x003d"/> <!-- = → = -->
+ <item key="0x3e" value="0x003e"/> <!-- > → > -->
+ <item key="0x3f" value="0x003f"/> <!-- ? → ? -->
+ <item key="0x40" value="0x0040"/> <!-- @ → @ -->
+ <item key="0x41" value="0x1161"/> <!-- A → ᅟᅡ -->
+ <item key="0x42" value="0x1107"/> <!-- B → ᄇᅠ -->
+ <item key="0x43" value="0x110e"/> <!-- C → ᄎᅠ -->
+ <item key="0x44" value="0x1103"/> <!-- D → ᄃᅠ -->
+ <item key="0x45" value="0x1166"/> <!-- E → ᅟᅦ -->
+ <item key="0x46" value="0x1111"/> <!-- F → ᄑᅠ -->
+ <item key="0x47" value="0x1100"/> <!-- G → ᄀᅠ -->
+ <item key="0x48" value="0x1112"/> <!-- H → ᄒᅠ -->
+ <item key="0x49" value="0x1175"/> <!-- I → ᅟᅵ -->
+ <item key="0x4a" value="0x110c"/> <!-- J → ᄌᅠ -->
+ <item key="0x4b" value="0x110f"/> <!-- K → ᄏᅠ -->
+ <item key="0x4c" value="0x1105"/> <!-- L → ᄅᅠ -->
+ <item key="0x4d" value="0x1106"/> <!-- M → ᄆᅠ -->
+ <item key="0x4e" value="0x1102"/> <!-- N → ᄂᅠ -->
+ <item key="0x4f" value="0x1169"/> <!-- O → ᅟᅩ -->
+ <item key="0x50" value="0x1111"/> <!-- P → ᄑᅠ -->
+ <item key="0x51" value="0x110f"/> <!-- Q → ᄏᅠ -->
+ <item key="0x52" value="0x1105"/> <!-- R → ᄅᅠ -->
+ <item key="0x53" value="0x1109"/> <!-- S → ᄉᅠ -->
+ <item key="0x54" value="0x1110"/> <!-- T → ᄐᅠ -->
+ <item key="0x55" value="0x116e"/> <!-- U → ᅟᅮ -->
+ <item key="0x56" value="0x1107"/> <!-- V → ᄇᅠ -->
+ <item key="0x57" value="0x116e"/> <!-- W → ᅟᅮ -->
+ <item key="0x58" value="0x110c"/> <!-- X → ᄌᅠ -->
+ <item key="0x59" value="0x1175"/> <!-- Y → ᅟᅵ -->
+ <item key="0x5a" value="0x110c"/> <!-- Z → ᄌᅠ -->
+ <item key="0x5b" value="0x005b"/> <!-- [ → [ -->
+ <item key="0x5c" value="0x005c"/> <!-- \ → \ -->
+ <item key="0x5d" value="0x005d"/> <!-- ] → ] -->
+ <item key="0x5e" value="0x005e"/> <!-- ^ → ^ -->
+ <item key="0x5f" value="0x005f"/> <!-- _ → _ -->
+ <item key="0x60" value="0x0060"/> <!-- ` → ` -->
+ <item key="0x61" value="0x1161"/> <!-- a → ᅟᅡ -->
+ <item key="0x62" value="0x1107"/> <!-- b → ᄇᅠ -->
+ <item key="0x63" value="0x110e"/> <!-- c → ᄎᅠ -->
+ <item key="0x64" value="0x1103"/> <!-- d → ᄃᅠ -->
+ <item key="0x65" value="0x1166"/> <!-- e → ᅟᅦ -->
+ <item key="0x66" value="0x1111"/> <!-- f → ᄑᅠ -->
+ <item key="0x67" value="0x1100"/> <!-- g → ᄀᅠ -->
+ <item key="0x68" value="0x1112"/> <!-- h → ᄒᅠ -->
+ <item key="0x69" value="0x1175"/> <!-- i → ᅟᅵ -->
+ <item key="0x6a" value="0x110c"/> <!-- j → ᄌᅠ -->
+ <item key="0x6b" value="0x110f"/> <!-- k → ᄏᅠ -->
+ <item key="0x6c" value="0x1105"/> <!-- l → ᄅᅠ -->
+ <item key="0x6d" value="0x1106"/> <!-- m → ᄆᅠ -->
+ <item key="0x6e" value="0x1102"/> <!-- n → ᄂᅠ -->
+ <item key="0x6f" value="0x1169"/> <!-- o → ᅟᅩ -->
+ <item key="0x70" value="0x1111"/> <!-- p → ᄑᅠ -->
+ <item key="0x71" value="0x110f"/> <!-- q → ᄏᅠ -->
+ <item key="0x72" value="0x1105"/> <!-- r → ᄅᅠ -->
+ <item key="0x73" value="0x1109"/> <!-- s → ᄉᅠ -->
+ <item key="0x74" value="0x1110"/> <!-- t → ᄐᅠ -->
+ <item key="0x75" value="0x116e"/> <!-- u → ᅟᅮ -->
+ <item key="0x76" value="0x1107"/> <!-- v → ᄇᅠ -->
+ <item key="0x77" value="0x116e"/> <!-- w → ᅟᅮ -->
+ <item key="0x78" value="0x11aa"/> <!-- x → ᅟᅠᆪ -->
+ <item key="0x79" value="0x1175"/> <!-- y → ᅟᅵ -->
+ <item key="0x7a" value="0x110c"/> <!-- z → ᄌᅠ -->
+ <item key="0x7b" value="0x007b"/> <!-- { → { -->
+ <item key="0x7c" value="0x007c"/> <!-- | → | -->
+ <item key="0x7d" value="0x007d"/> <!-- } → } -->
+ <item key="0x7e" value="0x007e"/> <!-- ~ → ~ -->
+ </map>
+
+ <combination id="0">
+ <item first="0x1100" second="0x1100" result="0x1101"/> <!-- ᄀ + ᄀ → ᄁ -->
+ <item first="0x1103" second="0x1103" result="0x1104"/> <!-- ᄃ + ᄃ → ᄄ -->
+ <item first="0x1107" second="0x1107" result="0x1108"/> <!-- ᄇ + ᄇ → ᄈ -->
+ <item first="0x1109" second="0x1109" result="0x110a"/> <!-- ᄉ + ᄉ → ᄊ -->
+ <item first="0x110c" second="0x110c" result="0x110d"/> <!-- ᄌ + ᄌ → ᄍ -->
+ <item first="0x110e" second="0x1112" result="0x110e"/> <!-- ᄎ + ᄒ → ᄎ -->
+ <item first="0x1161" second="0x1166" result="0x1162"/> <!-- ᅡ + ᅦ → ᅢ -->
+ <item first="0x1161" second="0x1175" result="0x1162"/> <!-- ᅡ + ᅵ → ᅢ -->
+ <item first="0x1163" second="0x1166" result="0x1164"/> <!-- ᅣ + ᅦ → ᅤ -->
+ <item first="0x1163" second="0x1175" result="0x1164"/> <!-- ᅣ + ᅵ → ᅤ -->
+ <item first="0x1166" second="0x1169" result="0x1165"/> <!-- ᅦ + ᅩ → ᅥ -->
+ <item first="0x1166" second="0x116e" result="0x1173"/> <!-- ᅦ + ᅮ → ᅳ -->
+ <item first="0x1168" second="0x1169" result="0x1167"/> <!-- ᅨ + ᅩ → ᅧ -->
+ <item first="0x1169" second="0x1161" result="0x116a"/> <!-- ᅩ + ᅡ → ᅪ -->
+ <item first="0x1169" second="0x1162" result="0x116b"/> <!-- ᅩ + ᅢ → ᅫ -->
+ <item first="0x1169" second="0x1175" result="0x116c"/> <!-- ᅩ + ᅵ → ᅬ -->
+ <item first="0x116a" second="0x1166" result="0x116b"/> <!-- ᅪ + ᅦ → ᅫ -->
+ <item first="0x116a" second="0x1175" result="0x116b"/> <!-- ᅪ + ᅵ → ᅫ -->
+ <item first="0x116e" second="0x1161" result="0x116a"/> <!-- ᅮ + ᅡ → ᅪ -->
+ <item first="0x116e" second="0x1165" result="0x116f"/> <!-- ᅮ + ᅥ → ᅯ -->
+ <item first="0x116e" second="0x1166" result="0x1170"/> <!-- ᅮ + ᅦ → ᅰ -->
+ <item first="0x116e" second="0x1169" result="0x116f"/> <!-- ᅮ + ᅩ → ᅯ -->
+ <item first="0x116e" second="0x1175" result="0x1171"/> <!-- ᅮ + ᅵ → ᅱ -->
+ <item first="0x1170" second="0x1169" result="0x116f"/> <!-- ᅰ + ᅩ → ᅯ -->
+ <item first="0x1173" second="0x1175" result="0x1174"/> <!-- ᅳ + ᅵ → ᅴ -->
+ <item first="0x1175" second="0x1161" result="0x1163"/> <!-- ᅵ + ᅡ → ᅣ -->
+ <item first="0x1175" second="0x1162" result="0x1164"/> <!-- ᅵ + ᅢ → ᅤ -->
+ <item first="0x1175" second="0x1165" result="0x1167"/> <!-- ᅵ + ᅥ → ᅧ -->
+ <item first="0x1175" second="0x1166" result="0x1168"/> <!-- ᅵ + ᅦ → ᅨ -->
+ <item first="0x1175" second="0x1169" result="0x116d"/> <!-- ᅵ + ᅩ → ᅭ -->
+ <item first="0x1175" second="0x116e" result="0x1172"/> <!-- ᅵ + ᅮ → ᅲ -->
+ <item first="0x11a8" second="0x11a8" result="0x11a9"/> <!-- ᆨ + ᆨ → ᆩ -->
+ <item first="0x11a8" second="0x11ba" result="0x11aa"/> <!-- ᆨ + ᆺ → ᆪ -->
+ <item first="0x11ab" second="0x11a8" result="0x11bc"/> <!-- ᆫ + ᆨ → ᆼ -->
+ <item first="0x11ab" second="0x11bd" result="0x11ac"/> <!-- ᆫ + ᆽ → ᆬ -->
+ <item first="0x11ab" second="0x11c2" result="0x11ad"/> <!-- ᆫ + ᇂ → ᆭ -->
+ <item first="0x11af" second="0x11a8" result="0x11b0"/> <!-- ᆯ + ᆨ → ᆰ -->
+ <item first="0x11af" second="0x11b7" result="0x11b1"/> <!-- ᆯ + ᆷ → ᆱ -->
+ <item first="0x11af" second="0x11b8" result="0x11b2"/> <!-- ᆯ + ᆸ → ᆲ -->
+ <item first="0x11af" second="0x11ba" result="0x11b3"/> <!-- ᆯ + ᆺ → ᆳ -->
+ <item first="0x11af" second="0x11c0" result="0x11b4"/> <!-- ᆯ + ᇀ → ᆴ -->
+ <item first="0x11af" second="0x11c1" result="0x11b5"/> <!-- ᆯ + ᇁ → ᆵ -->
+ <item first="0x11af" second="0x11c2" result="0x11b6"/> <!-- ᆯ + ᇂ → ᆶ -->
+ <item first="0x11b8" second="0x11ba" result="0x11b9"/> <!-- ᆸ + ᆺ → ᆹ -->
+ <item first="0x11ba" second="0x11ba" result="0x11bb"/> <!-- ᆺ + ᆺ → ᆻ -->
+ </combination>
+
+</hangul-keyboard>
diff --git a/hangul/Makefile.am b/hangul/Makefile.am
index e3213c4..5031b36 100644
--- a/hangul/Makefile.am
+++ b/hangul/Makefile.am
@@ -12,11 +12,16 @@ noinst_HEADERS = \
libhangul_la_SOURCES = \
hangulctype.c \
hangulinputcontext.c \
+ hangulkeyboard.c \
hanja.c
libhangul_la_CFLAGS = \
- -DLOCALEDIR=\"$(localedir)\" \
- -DLIBHANGUL_DEFAULT_HANJA_DIC=\"$(datadir)/libhangul/hanja/hanja.txt\"
+ -DLOCALEDIR=\"$(localedir)\" \
+ -DLIBHANGUL_DEFAULT_HANJA_DIC=\"$(pkgdatadir)/hanja/hanja.txt\" \
+ -DLIBHANGUL_DATA_DIR=\"$(pkgdatadir)\" \
+ -DTOP_SRCDIR=\"$(abs_top_srcdir)\" \
+ $(EXPAT_CFLAGS) \
+ $(NULL)
libhangul_la_LDFLAGS = -version-info $(LIBHANGUL_CURRENT):$(LIBHANGUL_REVISION):$(LIBHANGUL_AGE)
-libhangul_la_LIBADD =
+libhangul_la_LIBADD = $(EXPAT_LIBS)
diff --git a/hangul/hangul.h b/hangul/hangul.h
index fe85124..447e1e3 100644
--- a/hangul/hangul.h
+++ b/hangul/hangul.h
@@ -84,7 +84,9 @@ enum {
enum {
HANGUL_KEYBOARD_TYPE_JAMO,
HANGUL_KEYBOARD_TYPE_JASO,
- HANGUL_KEYBOARD_TYPE_ROMAJA
+ HANGUL_KEYBOARD_TYPE_ROMAJA,
+ HANGUL_KEYBOARD_TYPE_JAMO_YET,
+ HANGUL_KEYBOARD_TYPE_JASO_YET,
};
enum {
@@ -93,13 +95,19 @@ enum {
HANGUL_IC_OPTION_NON_CHOSEONG_COMBI,
};
+/* library */
+int hangul_init();
+int hangul_fini();
+
/* keyboard */
HangulKeyboard* hangul_keyboard_new(void);
void hangul_keyboard_delete(HangulKeyboard *keyboard);
-void hangul_keyboard_set_value(HangulKeyboard *keyboard,
- int key, ucschar value);
void hangul_keyboard_set_type(HangulKeyboard *keyboard, int type);
+unsigned int hangul_keyboard_list_get_count();
+const char* hangul_keyboard_list_get_keyboard_id(unsigned index_);
+const char* hangul_keyboard_list_get_keyboard_name(unsigned index_);
+
/* combination */
HangulCombination* hangul_combination_new(void);
void hangul_combination_delete(HangulCombination *combination);
@@ -126,15 +134,9 @@ void hangul_ic_set_keyboard(HangulInputContext *hic,
const HangulKeyboard *keyboard);
void hangul_ic_select_keyboard(HangulInputContext *hic,
const char* id);
-void hangul_ic_set_combination(HangulInputContext *hic,
- const HangulCombination *combination);
void hangul_ic_connect_callback(HangulInputContext* hic, const char* event,
void* callback, void* user_data);
-unsigned hangul_ic_get_n_keyboards();
-const char* hangul_ic_get_keyboard_id(unsigned index_);
-const char* hangul_ic_get_keyboard_name(unsigned index_);
-
const ucschar* hangul_ic_get_preedit_string(HangulInputContext *hic);
const ucschar* hangul_ic_get_commit_string(HangulInputContext *hic);
const ucschar* hangul_ic_flush(HangulInputContext *hic);
@@ -166,6 +168,15 @@ const char* hanja_get_comment(const Hanja* hanja);
}
#endif
+void hangul_keyboard_set_value(HangulKeyboard *keyboard,
+ int key, ucschar value) LIBHANGUL_DEPRECATED;
+void hangul_ic_set_combination(HangulInputContext *hic,
+ const HangulCombination *combination) LIBHANGUL_DEPRECATED;
+
+unsigned hangul_ic_get_n_keyboards() LIBHANGUL_DEPRECATED;
+const char* hangul_ic_get_keyboard_id(unsigned index_) LIBHANGUL_DEPRECATED;
+const char* hangul_ic_get_keyboard_name(unsigned index_) LIBHANGUL_DEPRECATED;
+
#undef LIBHANGUL_DEPRECATED
#endif /* libhangul_hangul_h */
diff --git a/hangul/hangulinputcontext.c b/hangul/hangulinputcontext.c
index 83ce52e..504d507 100644
--- a/hangul/hangulinputcontext.c
+++ b/hangul/hangulinputcontext.c
@@ -1,5 +1,5 @@
/* libhangul
- * Copyright (C) 2004 - 2009 Choe Hwanjin
+ * Copyright (C) 2004 - 2016 Choe Hwanjin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -175,8 +175,6 @@
#define FALSE 0
#endif
-#define HANGUL_KEYBOARD_TABLE_SIZE 0x80
-
typedef void (*HangulOnTranslate) (HangulInputContext*,
int,
ucschar*,
@@ -186,26 +184,6 @@ typedef bool (*HangulOnTransition) (HangulInputContext*,
const ucschar*,
void*);
-typedef struct _HangulCombinationItem HangulCombinationItem;
-
-struct _HangulKeyboard {
- int type;
- const char* id;
- const char* name;
- const ucschar* table;
- const HangulCombination* combination;
-};
-
-struct _HangulCombinationItem {
- uint32_t key;
- ucschar code;
-};
-
-struct _HangulCombination {
- int size;
- HangulCombinationItem *table;
-};
-
struct _HangulBuffer {
ucschar choseong;
ucschar jungseong;
@@ -239,113 +217,6 @@ struct _HangulInputContext {
unsigned int option_non_choseong_combi : 1;
};
-#include "hangulkeyboard.h"
-
-static const HangulCombination hangul_combination_default = {
- N_ELEMENTS(hangul_combination_table_default),
- (HangulCombinationItem*)hangul_combination_table_default
-};
-
-static const HangulCombination hangul_combination_romaja = {
- N_ELEMENTS(hangul_combination_table_romaja),
- (HangulCombinationItem*)hangul_combination_table_romaja
-};
-
-static const HangulCombination hangul_combination_full = {
- N_ELEMENTS(hangul_combination_table_full),
- (HangulCombinationItem*)hangul_combination_table_full
-};
-
-static const HangulCombination hangul_combination_ahn = {
- N_ELEMENTS(hangul_combination_table_ahn),
- (HangulCombinationItem*)hangul_combination_table_ahn
-};
-
-static const HangulKeyboard hangul_keyboard_2 = {
- HANGUL_KEYBOARD_TYPE_JAMO,
- "2",
- N_("Dubeolsik"),
- (ucschar*)hangul_keyboard_table_2,
- &hangul_combination_default
-};
-
-static const HangulKeyboard hangul_keyboard_2y = {
- HANGUL_KEYBOARD_TYPE_JAMO,
- "2y",
- N_("Dubeolsik Yetgeul"),
- (ucschar*)hangul_keyboard_table_2y,
- &hangul_combination_full
-};
-
-static const HangulKeyboard hangul_keyboard_32 = {
- HANGUL_KEYBOARD_TYPE_JASO,
- "32",
- N_("Sebeolsik Dubeol Layout"),
- (ucschar*)hangul_keyboard_table_32,
- &hangul_combination_default
-};
-
-static const HangulKeyboard hangul_keyboard_390 = {
- HANGUL_KEYBOARD_TYPE_JASO,
- "39",
- N_("Sebeolsik 390"),
- (ucschar*)hangul_keyboard_table_390,
- &hangul_combination_default
-};
-
-static const HangulKeyboard hangul_keyboard_3final = {
- HANGUL_KEYBOARD_TYPE_JASO,
- "3f",
- N_("Sebeolsik Final"),
- (ucschar*)hangul_keyboard_table_3final,
- &hangul_combination_default
-};
-
-static const HangulKeyboard hangul_keyboard_3sun = {
- HANGUL_KEYBOARD_TYPE_JASO,
- "3s",
- N_("Sebeolsik Noshift"),
- (ucschar*)hangul_keyboard_table_3sun,
- &hangul_combination_default
-};
-
-static const HangulKeyboard hangul_keyboard_3yet = {
- HANGUL_KEYBOARD_TYPE_JASO,
- "3y",
- N_("Sebeolsik Yetgeul"),
- (ucschar*)hangul_keyboard_table_3yet,
- &hangul_combination_full
-};
-
-static const HangulKeyboard hangul_keyboard_romaja = {
- HANGUL_KEYBOARD_TYPE_ROMAJA,
- "ro",
- N_("Romaja"),
- (ucschar*)hangul_keyboard_table_romaja,
- &hangul_combination_romaja
-};
-
-static const HangulKeyboard hangul_keyboard_ahn = {
- HANGUL_KEYBOARD_TYPE_JASO,
- "ahn",
- N_("Ahnmatae"),
- (ucschar*)hangul_keyboard_table_ahn,
- &hangul_combination_ahn
-};
-
-static const HangulKeyboard* hangul_keyboards[] = {
- &hangul_keyboard_2,
- &hangul_keyboard_2y,
- &hangul_keyboard_390,
- &hangul_keyboard_3final,
- &hangul_keyboard_3sun,
- &hangul_keyboard_3yet,
- &hangul_keyboard_32,
- &hangul_keyboard_romaja,
- &hangul_keyboard_ahn,
-};
-
-
static void hangul_buffer_push(HangulBuffer *buffer, ucschar ch);
static ucschar hangul_buffer_pop (HangulBuffer *buffer);
static ucschar hangul_buffer_peek(HangulBuffer *buffer);
@@ -356,162 +227,6 @@ static int hangul_buffer_get_jamo_string(HangulBuffer *buffer, ucschar *buf,
static void hangul_ic_flush_internal(HangulInputContext *hic);
-HangulKeyboard*
-hangul_keyboard_new()
-{
- HangulKeyboard *keyboard = malloc(sizeof(HangulKeyboard));
- if (keyboard != NULL) {
- ucschar* table = malloc(sizeof(ucschar) * HANGUL_KEYBOARD_TABLE_SIZE);
- if (table != NULL) {
- int i;
- for (i = 0; i < HANGUL_KEYBOARD_TABLE_SIZE; i++)
- table[i] = 0;
-
- keyboard->table = table;
- return keyboard;
- }
- free(keyboard);
- }
-
- return NULL;
-}
-
-static ucschar
-hangul_keyboard_get_value(const HangulKeyboard *keyboard, int key)
-{
- if (keyboard != NULL) {
- if (key >= 0 && key < HANGUL_KEYBOARD_TABLE_SIZE)
- return keyboard->table[key];
- }
-
- return 0;
-}
-
-void
-hangul_keyboard_set_value(HangulKeyboard *keyboard, int key, ucschar value)
-{
- if (keyboard != NULL) {
- if (key >= 0 && key < HANGUL_KEYBOARD_TABLE_SIZE) {
- ucschar* table = (ucschar*)keyboard->table;
- table[key] = value;
- }
- }
-}
-
-static int
-hangul_keyboard_get_type(const HangulKeyboard *keyboard)
-{
- int type = 0;
- if (keyboard != NULL) {
- type = keyboard->type;
- }
- return type;
-}
-
-void
-hangul_keyboard_set_type(HangulKeyboard *keyboard, int type)
-{
- if (keyboard != NULL) {
- keyboard->type = type;
- }
-}
-
-void
-hangul_keyboard_delete(HangulKeyboard *keyboard)
-{
- if (keyboard != NULL)
- free(keyboard);
-}
-
-HangulCombination*
-hangul_combination_new()
-{
- HangulCombination *combination = malloc(sizeof(HangulCombination));
- if (combination != NULL) {
- combination->size = 0;
- combination->table = NULL;
- return combination;
- }
-
- return NULL;
-}
-
-void
-hangul_combination_delete(HangulCombination *combination)
-{
- if (combination != NULL) {
- if (combination->table != NULL)
- free(combination->table);
- free(combination);
- }
-}
-
-static uint32_t
-hangul_combination_make_key(ucschar first, ucschar second)
-{
- return first << 16 | second;
-}
-
-bool
-hangul_combination_set_data(HangulCombination* combination,
- ucschar* first, ucschar* second, ucschar* result,
- unsigned int n)
-{
- if (combination == NULL)
- return false;
-
- if (n == 0 || n > ULONG_MAX / sizeof(HangulCombinationItem))
- return false;
-
- combination->table = malloc(sizeof(HangulCombinationItem) * n);
- if (combination->table != NULL) {
- int i;
-
- combination->size = n;
- for (i = 0; i < n; i++) {
- combination->table[i].key = hangul_combination_make_key(first[i], second[i]);
- combination->table[i].code = result[i];
- }
- return true;
- }
-
- return false;
-}
-
-static int
-hangul_combination_cmp(const void* p1, const void* p2)
-{
- const HangulCombinationItem *item1 = p1;
- const HangulCombinationItem *item2 = p2;
-
- /* key는 unsigned int이므로 단순히 빼서 리턴하면 안된다.
- * 두 수의 차가 큰 경우 int로 변환하면서 음수가 될 수 있다. */
- if (item1->key < item2->key)
- return -1;
- else if (item1->key > item2->key)
- return 1;
- else
- return 0;
-}
-
-ucschar
-hangul_combination_combine(const HangulCombination* combination,
- ucschar first, ucschar second)
-{
- HangulCombinationItem *res;
- HangulCombinationItem key;
-
- if (combination == NULL)
- return 0;
-
- key.key = hangul_combination_make_key(first, second);
- res = bsearch(&key, combination->table, combination->size,
- sizeof(combination->table[0]), hangul_combination_cmp);
- if (res != NULL)
- return res->code;
-
- return 0;
-}
static bool
hangul_buffer_is_empty(HangulBuffer *buffer)
@@ -845,7 +560,10 @@ hangul_ic_choseong_to_jongseong(HangulInputContext* hic, ucschar cho)
} else {
/* 옛글 조합 규칙을 사용하는 자판의 경우에는 종성이 conjoinable
* 하지 않아도 상관없다 */
- if (hic->keyboard->combination == &hangul_combination_full) {
+ int type = hangul_keyboard_get_type(hic->keyboard);
+ switch (type) {
+ case HANGUL_KEYBOARD_TYPE_JAMO_YET:
+ case HANGUL_KEYBOARD_TYPE_JASO_YET:
return jong;
}
}
@@ -868,8 +586,7 @@ hangul_ic_combine(HangulInputContext* hic, ucschar first, ucschar second)
}
ucschar combined = 0;
- combined = hangul_combination_combine(hic->keyboard->combination,
- first, second);
+ combined = hangul_keyboard_combine(hic->keyboard, 0, first, second);
if (!hic->option_non_choseong_combi) {
if (hangul_is_choseong(first) && hangul_is_choseong(second) &&
@@ -1362,7 +1079,7 @@ hangul_ic_process(HangulInputContext *hic, int ascii)
hic->preedit_string[0] = 0;
hic->commit_string[0] = 0;
- c = hangul_keyboard_get_value(hic->keyboard, ascii);
+ c = hangul_keyboard_get_mapping(hic->keyboard, 0, ascii);
if (hic->on_translate != NULL)
hic->on_translate(hic, ascii, &c, hic->on_translate_data);
@@ -1370,12 +1087,16 @@ hangul_ic_process(HangulInputContext *hic, int ascii)
return hangul_ic_backspace(hic);
}
- if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JAMO)
- return hangul_ic_process_jamo(hic, c);
- else if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JASO)
+ int type = hangul_keyboard_get_type(hic->keyboard);
+ switch (type) {
+ case HANGUL_KEYBOARD_TYPE_JASO:
+ case HANGUL_KEYBOARD_TYPE_JASO_YET:
return hangul_ic_process_jaso(hic, c);
- else
+ case HANGUL_KEYBOARD_TYPE_ROMAJA:
return hangul_ic_process_romaja(hic, ascii, c);
+ default:
+ return hangul_ic_process_jamo(hic, c);
+ }
}
/**
@@ -1676,25 +1397,6 @@ hangul_ic_set_keyboard(HangulInputContext *hic, const HangulKeyboard* keyboard)
hic->keyboard = keyboard;
}
-static const HangulKeyboard*
-hangul_ic_get_keyboard_by_id(const char* id)
-{
- unsigned i;
- unsigned n;
-
- /* hangul_keyboards 테이블은 id 순으로 정렬되어 있지 않으므로
- * binary search를 할수 없고 linear search를 한다. */
- n = hangul_ic_get_n_keyboards();
- for (i = 0; i < n; ++i) {
- const HangulKeyboard* keyboard = hangul_keyboards[i];
- if (strcmp(id, keyboard->id) == 0) {
- return keyboard;
- }
- }
-
- return NULL;
-}
-
/**
* @ingroup hangulic
* @brief @ref HangulInputContext 의 자판 배열을 바꾸는 함수
@@ -1729,12 +1431,8 @@ hangul_ic_select_keyboard(HangulInputContext *hic, const char* id)
if (id == NULL)
id = "2";
- keyboard = hangul_ic_get_keyboard_by_id(id);
- if (keyboard != NULL) {
- hic->keyboard = keyboard;
- } else {
- hic->keyboard = &hangul_keyboard_2;
- }
+ keyboard = hangul_keyboard_list_get_keyboard(id);
+ hic->keyboard = keyboard;
}
void
@@ -1811,36 +1509,19 @@ hangul_ic_delete(HangulInputContext *hic)
unsigned int
hangul_ic_get_n_keyboards()
{
- return N_ELEMENTS(hangul_keyboards);
+ return hangul_keyboard_list_get_count();
}
const char*
hangul_ic_get_keyboard_id(unsigned index_)
{
- if (index_ < N_ELEMENTS(hangul_keyboards)) {
- return hangul_keyboards[index_]->id;
- }
-
- return NULL;
+ return hangul_keyboard_list_get_keyboard_id(index_);
}
const char*
hangul_ic_get_keyboard_name(unsigned index_)
{
-#ifdef ENABLE_NLS
- static bool isGettextInitialized = false;
- if (!isGettextInitialized) {
- isGettextInitialized = true;
- bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
- }
-#endif
-
- if (index_ < N_ELEMENTS(hangul_keyboards)) {
- return _(hangul_keyboards[index_]->name);
- }
-
- return NULL;
+ return hangul_keyboard_list_get_keyboard_name(index_);
}
/**
@@ -1869,3 +1550,19 @@ hangul_ic_is_transliteration(HangulInputContext *hic)
return false;
}
+
+int
+hangul_init()
+{
+ int res;
+ res = hangul_keyboard_list_init();
+ return res;
+}
+
+int
+hangul_fini()
+{
+ int res;
+ res = hangul_keyboard_list_fini();
+ return res;
+}
diff --git a/hangul/hangulinternals.h b/hangul/hangulinternals.h
index 70f8857..8fb0d70 100644
--- a/hangul/hangulinternals.h
+++ b/hangul/hangulinternals.h
@@ -1,7 +1,27 @@
+/* libhangul
+ * Copyright (C) 2016 Choe Hwanjin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
#ifndef libhangul_hangulinternals_h
#define libhangul_hangulinternals_h
#define N_ELEMENTS(array) (sizeof (array) / sizeof ((array)[0]))
+#ifndef countof
+#define countof(array) (sizeof (array) / sizeof ((array)[0]))
+#endif
ucschar hangul_jongseong_get_diff(ucschar prevjong, ucschar jong);
@@ -9,4 +29,15 @@ ucschar hangul_choseong_to_jongseong(ucschar ch);
ucschar hangul_jongseong_to_choseong(ucschar ch);
void hangul_jongseong_decompose(ucschar ch, ucschar* jong, ucschar* cho);
+int hangul_keyboard_get_type(const HangulKeyboard *keyboard);
+ucschar hangul_keyboard_combine(const HangulKeyboard* keyboard,
+ unsigned id, ucschar first, ucschar second);
+ucschar hangul_keyboard_get_mapping(const HangulKeyboard* keyboard,
+ int tableid, unsigned key);
+
+int hangul_keyboard_list_init();
+int hangul_keyboard_list_fini();
+
+const HangulKeyboard* hangul_keyboard_list_get_keyboard(const char* id);
+
#endif /* libhangul_hangulinternals_h */
diff --git a/hangul/hangulkeyboard.c b/hangul/hangulkeyboard.c
new file mode 100644
index 0000000..168774a
--- /dev/null
+++ b/hangul/hangulkeyboard.c
@@ -0,0 +1,950 @@
+/* libhangul
+ * Copyright (C) 2016 Choe Hwanjin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <locale.h>
+#include <glob.h>
+#include <libgen.h>
+#include <expat.h>
+
+#include "hangul-gettext.h"
+#include "hangul.h"
+#include "hangulinternals.h"
+
+
+#define LIBHANGUL_KEYBOARD_DIR LIBHANGUL_DATA_DIR "/keyboards"
+//#define LIBHANGUL_KEYBOARD_DIR TOP_SRCDIR "/data/keyboards"
+
+#define HANGUL_KEYBOARD_TABLE_SIZE 0x80
+
+typedef struct _HangulCombinationItem HangulCombinationItem;
+
+struct _HangulCombinationItem {
+ uint32_t key;
+ ucschar code;
+};
+
+struct _HangulCombination {
+ size_t size;
+ size_t size_alloced;
+ HangulCombinationItem *table;
+
+ bool is_static;
+};
+
+struct _HangulKeyboard {
+ char* id;
+ char* name;
+ ucschar* table[4];
+ HangulCombination* combination[4];
+
+ int type;
+ bool is_static;
+};
+
+typedef struct _HangulKeyboardList {
+ size_t n;
+ size_t nalloced;
+ HangulKeyboard** keyboards;
+} HangulKeyboardList;
+
+#include "hangulkeyboard.h"
+
+static const HangulCombination hangul_combination_default = {
+ countof(hangul_combination_table_default),
+ countof(hangul_combination_table_default),
+ (HangulCombinationItem*)hangul_combination_table_default,
+ true
+};
+
+static const HangulCombination hangul_combination_romaja = {
+ countof(hangul_combination_table_romaja),
+ countof(hangul_combination_table_romaja),
+ (HangulCombinationItem*)hangul_combination_table_romaja,
+ true
+};
+
+static const HangulCombination hangul_combination_full = {
+ countof(hangul_combination_table_full),
+ countof(hangul_combination_table_full),
+ (HangulCombinationItem*)hangul_combination_table_full,
+ true
+};
+
+static const HangulCombination hangul_combination_ahn = {
+ countof(hangul_combination_table_ahn),
+ countof(hangul_combination_table_ahn),
+ (HangulCombinationItem*)hangul_combination_table_ahn,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_2 = {
+ (char*)"2",
+ (char*)N_("Dubeolsik"),
+ { (ucschar*)hangul_keyboard_table_2, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_default, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JAMO,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_2y = {
+ (char*)"2y",
+ (char*)N_("Dubeolsik Yetgeul"),
+ { (ucschar*)hangul_keyboard_table_2y, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_full, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JAMO_YET,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_32 = {
+ (char*)"32",
+ (char*)N_("Sebeolsik Dubeol Layout"),
+ { (ucschar*)hangul_keyboard_table_32, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_default, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JASO,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_390 = {
+ (char*)"39",
+ (char*)N_("Sebeolsik 390"),
+ { (ucschar*)hangul_keyboard_table_390, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_default, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JASO,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_3final = {
+ (char*)"3f",
+ (char*)N_("Sebeolsik Final"),
+ { (ucschar*)hangul_keyboard_table_3final, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_default, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JASO,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_3sun = {
+ (char*)"3s",
+ (char*)N_("Sebeolsik Noshift"),
+ { (ucschar*)hangul_keyboard_table_3sun, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_default, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JASO,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_3yet = {
+ (char*)"3y",
+ (char*)N_("Sebeolsik Yetgeul"),
+ { (ucschar*)hangul_keyboard_table_3yet, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_full, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JASO_YET,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_romaja = {
+ (char*)"ro",
+ (char*)N_("Romaja"),
+ { (ucschar*)hangul_keyboard_table_romaja, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_romaja, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_ROMAJA,
+ true
+};
+
+static const HangulKeyboard hangul_keyboard_ahn = {
+ (char*)"ahn",
+ (char*)N_("Ahnmatae"),
+ { (ucschar*)hangul_keyboard_table_ahn, NULL, NULL, NULL },
+ { (HangulCombination*)&hangul_combination_ahn, NULL, NULL, NULL },
+ HANGUL_KEYBOARD_TYPE_JASO,
+ true
+};
+
+static const HangulKeyboard* hangul_builtin_keyboards[] = {
+ &hangul_keyboard_2,
+ &hangul_keyboard_2y,
+ &hangul_keyboard_390,
+ &hangul_keyboard_3final,
+ &hangul_keyboard_3sun,
+ &hangul_keyboard_3yet,
+ &hangul_keyboard_32,
+ &hangul_keyboard_romaja,
+ &hangul_keyboard_ahn,
+};
+static unsigned int hangul_builtin_keyboard_count = countof(hangul_builtin_keyboards);
+
+static HangulKeyboardList hangul_keyboards = { 0, 0, NULL };
+
+typedef struct _HangulKeyboardLoadContext {
+ const char* path;
+ HangulKeyboard* keyboard;
+ int current_id;
+ const char* current_element;
+ bool save_name;
+} HangulKeyboardLoadContext;
+
+static void hangul_keyboard_parse_file(const char* path, void* user_data);
+static bool hangul_keyboard_list_append(HangulKeyboard* keyboard);
+
+
+HangulCombination*
+hangul_combination_new()
+{
+ HangulCombination *combination = malloc(sizeof(HangulCombination));
+ if (combination != NULL) {
+ combination->size = 0;
+ combination->size_alloced = 0;
+ combination->table = NULL;
+ combination->is_static = false;
+ return combination;
+ }
+
+ return NULL;
+}
+
+void
+hangul_combination_delete(HangulCombination *combination)
+{
+ if (combination == NULL)
+ return;
+
+ if (combination->is_static)
+ return;
+
+ if (combination->table != NULL)
+ free(combination->table);
+
+ free(combination);
+}
+
+static uint32_t
+hangul_combination_make_key(ucschar first, ucschar second)
+{
+ return first << 16 | second;
+}
+
+bool
+hangul_combination_set_data(HangulCombination* combination,
+ ucschar* first, ucschar* second, ucschar* result,
+ unsigned int n)
+{
+ if (combination == NULL)
+ return false;
+
+ if (n == 0 || n > ULONG_MAX / sizeof(HangulCombinationItem))
+ return false;
+
+ combination->table = malloc(sizeof(HangulCombinationItem) * n);
+ if (combination->table != NULL) {
+ int i;
+
+ combination->size = n;
+ for (i = 0; i < n; i++) {
+ combination->table[i].key = hangul_combination_make_key(first[i], second[i]);
+ combination->table[i].code = result[i];
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+hangul_combination_add_item(HangulCombination* combination,
+ ucschar first, ucschar second, ucschar result)
+{
+ if (combination == NULL)
+ return false;
+
+ if (combination->is_static)
+ return false;
+
+ if (combination->size >= combination->size_alloced) {
+ size_t size_need = combination->size_alloced * 2;
+ if (size_need == 0) {
+ // 처음 할당할 때에는 64개를 기본값으로 한다.
+ size_need = 64;
+ }
+
+ HangulCombinationItem* table = combination->table;
+ table = realloc(table, size_need * sizeof(table[0]));
+ if (table == NULL)
+ return false;
+
+ combination->size_alloced = size_need;
+ combination->table = table;
+ }
+
+ uint32_t key = hangul_combination_make_key(first, second);
+ size_t i = combination->size;
+ combination->table[i].key = key;
+ combination->table[i].code = result;
+ combination->size = i + 1;
+ return true;
+}
+
+static int
+hangul_combination_cmp(const void* p1, const void* p2)
+{
+ const HangulCombinationItem *item1 = p1;
+ const HangulCombinationItem *item2 = p2;
+
+ /* key는 unsigned int이므로 단순히 빼서 리턴하면 안된다.
+ * 두 수의 차가 큰 경우 int로 변환하면서 음수가 될 수 있다. */
+ if (item1->key < item2->key)
+ return -1;
+ else if (item1->key > item2->key)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+hangul_combination_sort(HangulCombination* combination)
+{
+ if (combination == NULL)
+ return;
+
+ if (combination->is_static)
+ return;
+
+ qsort(combination->table, combination->size,
+ sizeof(combination->table[0]), hangul_combination_cmp);
+}
+
+static ucschar
+hangul_combination_combine(const HangulCombination* combination,
+ ucschar first, ucschar second)
+{
+ HangulCombinationItem *res;
+ HangulCombinationItem key;
+
+ if (combination == NULL)
+ return 0;
+
+ key.key = hangul_combination_make_key(first, second);
+ res = bsearch(&key, combination->table, combination->size,
+ sizeof(combination->table[0]), hangul_combination_cmp);
+ if (res != NULL)
+ return res->code;
+
+ return 0;
+}
+
+HangulKeyboard*
+hangul_keyboard_new()
+{
+ HangulKeyboard *keyboard = malloc(sizeof(HangulKeyboard));
+ if (keyboard == NULL)
+ return NULL;
+
+ keyboard->id = NULL;
+ keyboard->name = NULL;
+
+ keyboard->table[0] = NULL;
+ keyboard->table[1] = NULL;
+ keyboard->table[2] = NULL;
+ keyboard->table[3] = NULL;
+
+ keyboard->combination[0] = NULL;
+ keyboard->combination[1] = NULL;
+ keyboard->combination[2] = NULL;
+ keyboard->combination[3] = NULL;
+
+ keyboard->type = HANGUL_KEYBOARD_TYPE_JAMO;
+ keyboard->is_static = false;
+
+ return keyboard;
+}
+
+static void
+hangul_keyboard_set_id(HangulKeyboard* keyboard, const char* id)
+{
+ if (keyboard == NULL)
+ return;
+
+ if (keyboard->is_static)
+ return;
+
+ free(keyboard->id);
+ keyboard->id = strdup(id);
+}
+
+static void
+hangul_keyboard_set_name(HangulKeyboard* keyboard, const char* name)
+{
+ if (keyboard == NULL)
+ return;
+
+ if (keyboard->is_static)
+ return;
+
+ free(keyboard->name);
+ keyboard->name = strdup(name);
+}
+
+ucschar
+hangul_keyboard_get_mapping(const HangulKeyboard* keyboard, int tableid, unsigned key)
+{
+ if (keyboard == NULL)
+ return 0;
+
+ if (tableid >= countof(keyboard->table))
+ return 0;
+
+ if (key >= HANGUL_KEYBOARD_TABLE_SIZE)
+ return 0;
+
+ ucschar* table = keyboard->table[tableid];
+ if (table == NULL)
+ return 0;
+
+ return table[key];
+}
+
+static void
+hangul_keyboard_set_mapping(HangulKeyboard *keyboard, int tableid, unsigned key, ucschar value)
+{
+ if (keyboard == NULL)
+ return;
+
+ if (tableid >= countof(keyboard->table))
+ return;
+
+ if (key >= HANGUL_KEYBOARD_TABLE_SIZE)
+ return;
+
+ if (keyboard->table[tableid] == NULL) {
+ ucschar* new_table = malloc(sizeof(ucschar) * HANGUL_KEYBOARD_TABLE_SIZE);
+ if (new_table == NULL)
+ return;
+
+ unsigned i;
+ for (i = 0; i < HANGUL_KEYBOARD_TABLE_SIZE; ++i) {
+ new_table[i] = 0;
+ }
+ keyboard->table[tableid] = new_table;
+ }
+
+ ucschar* table = keyboard->table[tableid];
+ table[key] = value;
+}
+
+void
+hangul_keyboard_set_value(HangulKeyboard *keyboard, int key, ucschar value)
+{
+ hangul_keyboard_set_mapping(keyboard, 0, key, value);
+}
+
+int
+hangul_keyboard_get_type(const HangulKeyboard *keyboard)
+{
+ int type = 0;
+ if (keyboard != NULL) {
+ type = keyboard->type;
+ }
+ return type;
+}
+
+void
+hangul_keyboard_set_type(HangulKeyboard *keyboard, int type)
+{
+ if (keyboard != NULL) {
+ keyboard->type = type;
+ }
+}
+
+void
+hangul_keyboard_delete(HangulKeyboard *keyboard)
+{
+ if (keyboard == NULL)
+ return;
+
+ if (keyboard->is_static)
+ return;
+
+ free(keyboard->id);
+ free(keyboard->name);
+
+ unsigned i;
+ for (i = 0; i < countof(keyboard->table); ++i) {
+ if (keyboard->table[i] != NULL) {
+ free(keyboard->table[i]);
+ }
+ }
+
+ for (i = 0; i < countof(keyboard->combination); ++i) {
+ if (keyboard->combination[i] != NULL) {
+ hangul_combination_delete(keyboard->combination[i]);
+ }
+ }
+
+ free(keyboard);
+}
+
+ucschar
+hangul_keyboard_combine(const HangulKeyboard* keyboard,
+ unsigned id, ucschar first, ucschar second)
+{
+ if (keyboard == NULL)
+ return 0;
+
+ if (id >= countof(keyboard->combination))
+ return 0;
+
+ HangulCombination* combination = keyboard->combination[id];
+ ucschar res = hangul_combination_combine(combination, first, second);
+ return res;
+}
+
+static const char*
+attr_lookup(const char** attr, const char* name)
+{
+ if (attr == NULL)
+ return NULL;
+
+ int i;
+ for (i = 0; attr[i] != NULL; i += 2) {
+ if (strcmp(attr[i], name) == 0) {
+ return attr[i + 1];
+ }
+ }
+
+ return NULL;
+}
+
+static unsigned int
+attr_lookup_as_uint(const char** attr, const char* name)
+{
+ const char* valuestr = attr_lookup(attr, name);
+ if (valuestr == NULL)
+ return 0;
+
+ unsigned int value = strtoul(valuestr, NULL, 0);
+ return value;
+}
+
+static void XMLCALL
+on_element_start(void* data, const XML_Char* element, const XML_Char** attr)
+{
+ HangulKeyboardLoadContext* context = (HangulKeyboardLoadContext*)data;
+
+ if (strcmp(element, "hangul-keyboard") == 0) {
+ if (context->keyboard != NULL) {
+ hangul_keyboard_delete(context->keyboard);
+ }
+ context->keyboard = hangul_keyboard_new();
+
+ const char* id = attr_lookup(attr, "id");
+ hangul_keyboard_set_id(context->keyboard, id);
+
+ const char* typestr = attr_lookup(attr, "type");
+ int type = HANGUL_KEYBOARD_TYPE_JAMO;
+ if (strcmp(typestr, "jamo") == 0) {
+ type = HANGUL_KEYBOARD_TYPE_JAMO;
+ } else if (strcmp(typestr, "jamo-yet") == 0) {
+ type = HANGUL_KEYBOARD_TYPE_JAMO_YET;
+ } else if (strcmp(typestr, "jaso") == 0) {
+ type = HANGUL_KEYBOARD_TYPE_JASO;
+ } else if (strcmp(typestr, "jaso-yet") == 0) {
+ type = HANGUL_KEYBOARD_TYPE_JASO_YET;
+ } else if (strcmp(typestr, "romaja") == 0) {
+ type = HANGUL_KEYBOARD_TYPE_ROMAJA;
+ }
+
+ hangul_keyboard_set_type(context->keyboard, type);
+ } else if (strcmp(element, "name") == 0) {
+ if (context->keyboard == NULL)
+ return;
+
+ const char* lang = attr_lookup(attr, "xml:lang");
+ if (lang == NULL) {
+ context->save_name = true;
+ } else {
+ const char* locale = setlocale(LC_ALL, NULL);
+ size_t n = strlen(lang);
+ if (strncmp(lang, locale, n) == 0) {
+ context->save_name = true;
+ }
+ }
+ context->current_element = "name";
+ } else if (strcmp(element, "map") == 0) {
+ if (context->keyboard == NULL)
+ return;
+
+ unsigned int id = attr_lookup_as_uint(attr, "id");
+ if (id < countof(context->keyboard->table)) {
+ context->current_id = id;
+ context->current_element = "map";
+ }
+ } else if (strcmp(element, "combination") == 0) {
+ if (context->keyboard == NULL)
+ return;
+
+ unsigned int id = attr_lookup_as_uint(attr, "id");
+ if (id < countof(context->keyboard->combination)) {
+ if (context->keyboard->combination[id] != NULL) {
+ hangul_combination_delete(context->keyboard->combination[id]);
+ }
+
+ context->current_id = id;
+ context->current_element = "combination";
+ context->keyboard->combination[id] = hangul_combination_new();
+ }
+ } else if (strcmp(element, "item") == 0) {
+ if (context->keyboard == NULL)
+ return;
+
+ unsigned int id = context->current_id;
+ if (strcmp(context->current_element, "map") == 0) {
+ HangulKeyboard* keyboard = context->keyboard;
+ unsigned int key = attr_lookup_as_uint(attr, "key");
+ unsigned int value = attr_lookup_as_uint(attr, "value");
+ hangul_keyboard_set_mapping(keyboard, id, key, value);
+ } else if (strcmp(context->current_element, "combination") == 0) {
+ HangulCombination* combination = context->keyboard->combination[id];
+ unsigned int first = attr_lookup_as_uint(attr, "first");
+ unsigned int second = attr_lookup_as_uint(attr, "second");
+ unsigned int result = attr_lookup_as_uint(attr, "result");
+ hangul_combination_add_item(combination, first, second, result);
+ }
+ } else if (strcmp(element, "include") == 0) {
+ const char* file = attr_lookup(attr, "file");
+ if (file == NULL)
+ return;
+
+ size_t n = strlen(file) + strlen(context->path) + 1;
+ char* path = malloc(n);
+ if (path == NULL)
+ return;
+
+ if (file[0] == '/') {
+ strncpy(path, file, n);
+ } else {
+ char* orig_path = strdup(context->path);
+ char* dir = dirname(orig_path);
+ snprintf(path, n, "%s/%s", dir, file);
+ free(orig_path);
+ }
+
+ hangul_keyboard_parse_file(path, context);
+ free(path);
+ }
+}
+
+static void XMLCALL
+on_element_end(void* data, const XML_Char* element)
+{
+ HangulKeyboardLoadContext* context = (HangulKeyboardLoadContext*)data;
+
+ if (context->keyboard == NULL)
+ return;
+
+ if (strcmp(element, "name") == 0) {
+ context->current_element = "";
+ context->save_name = false;
+ } else if (strcmp(element, "map") == 0) {
+ context->current_id = 0;
+ context->current_element = "";
+ } else if (strcmp(element, "combination") == 0) {
+ unsigned int id = context->current_id;
+ HangulCombination* combination = context->keyboard->combination[id];
+ hangul_combination_sort(combination);
+ context->current_id = 0;
+ context->current_element = "";
+ }
+}
+
+static void XMLCALL
+on_char_data(void* data, const XML_Char* s, int len)
+{
+ HangulKeyboardLoadContext* context = (HangulKeyboardLoadContext*)data;
+
+ if (context->keyboard == NULL)
+ return;
+
+ if (strcmp(context->current_element, "name") == 0) {
+ if (context->save_name) {
+ char buf[1024];
+ if (len >= sizeof(buf))
+ len = sizeof(buf) - 1;
+ memcpy(buf, s, len);
+ buf[len] = '\0';
+ hangul_keyboard_set_name(context->keyboard, buf);
+ }
+ }
+}
+
+static void
+hangul_keyboard_parse_file(const char* path, void* user_data)
+{
+ XML_Parser parser = XML_ParserCreate(NULL);
+
+ XML_SetUserData(parser, user_data);
+ XML_SetElementHandler(parser, on_element_start, on_element_end);
+ XML_SetCharacterDataHandler(parser, on_char_data);
+
+ FILE* file = fopen(path, "r");
+ if (file == NULL) {
+ goto done;
+ }
+
+ char buf[8192];
+
+ while (true) {
+ size_t n = fread(buf, 1, sizeof(buf), file);
+ int is_final = feof(file);
+ int res = XML_Parse(parser, buf, n, is_final);
+ if (res == XML_STATUS_ERROR) {
+ goto close;
+ }
+ if (is_final)
+ break;
+ }
+
+close:
+ fclose(file);
+done:
+ XML_ParserFree(parser);
+}
+
+static HangulKeyboard*
+hangul_keyboard_new_from_file(const char* path)
+{
+ HangulKeyboardLoadContext context = { path, NULL, 0, "" };
+
+ hangul_keyboard_parse_file(path, &context);
+
+ return context.keyboard;
+}
+
+static unsigned
+hangul_keyboard_list_load_dir(const char* path)
+{
+ char pattern[PATH_MAX];
+ snprintf(pattern, sizeof(pattern), "%s/*.xml", path);
+
+ glob_t result;
+ int res = glob(pattern, GLOB_ERR, NULL, &result);
+ if (res != 0)
+ return 0;
+
+ size_t i;
+ for (i = 0; i < result.gl_pathc; ++i) {
+ HangulKeyboard* keyboard = hangul_keyboard_new_from_file(result.gl_pathv[i]);
+ if (keyboard == NULL)
+ continue;
+ hangul_keyboard_list_append(keyboard);
+ }
+
+ globfree(&result);
+
+ return hangul_keyboards.n;
+}
+
+static void
+hangul_keyboard_list_clear()
+{
+ size_t i;
+ for (i = 0; i < hangul_keyboards.n; ++i) {
+ hangul_keyboard_delete(hangul_keyboards.keyboards[i]);
+ }
+
+ free(hangul_keyboards.keyboards);
+
+ hangul_keyboards.n = 0;
+ hangul_keyboards.nalloced = 0;
+ hangul_keyboards.keyboards = NULL;
+}
+
+int
+hangul_keyboard_list_init()
+{
+ /* hangul_init을 호출하면 builtin keyboard는 disable되도록 처리한다.
+ * 기본 자판은 외부 파일로 부터 로딩하는 것이 기본 동작이고
+ * builtin 키보드는 하위 호환을 위해 남겨둔다. */
+ hangul_builtin_keyboard_count = 0;
+
+ unsigned n = 0;
+ /* libhangul data dir에서 keyboard 로딩 */
+ n += hangul_keyboard_list_load_dir(LIBHANGUL_KEYBOARD_DIR);
+
+ /* 유저의 개별 키보드 파일 로딩 */
+ char user_data_dir[PATH_MAX];
+ char* xdg_data_home = getenv("XDG_DATA_HOME");
+ if (xdg_data_home == NULL) {
+ char* home_dir = getenv("HOME");
+ snprintf(user_data_dir, sizeof(user_data_dir),
+ "%s/.local/share/libhangul/keyboards", home_dir);
+ } else {
+ snprintf(user_data_dir, sizeof(user_data_dir),
+ "%s/libhangul/keyboards", xdg_data_home);
+ }
+ n += hangul_keyboard_list_load_dir(user_data_dir);
+
+ if (n == 0)
+ return 1;
+
+ return 0;
+}
+
+int
+hangul_keyboard_list_fini()
+{
+ hangul_keyboard_list_clear();
+ hangul_builtin_keyboard_count = countof(hangul_builtin_keyboards);
+ return 0;
+}
+
+static char*
+hangul_builtin_keyboard_list_get_keyboard_id(unsigned index_)
+{
+ if (index_ >= hangul_builtin_keyboard_count)
+ return NULL;
+
+ const HangulKeyboard* keyboard = hangul_builtin_keyboards[index_];
+ if (keyboard == NULL)
+ return NULL;
+
+ return keyboard->id;
+}
+
+static const char*
+hangul_builtin_keyboard_list_get_keyboard_name(unsigned index_)
+{
+#ifdef ENABLE_NLS
+ static bool isGettextInitialized = false;
+ if (!isGettextInitialized) {
+ isGettextInitialized = true;
+ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ }
+#endif
+
+ if (index_ >= hangul_builtin_keyboard_count)
+ return NULL;
+
+ const HangulKeyboard* keyboard = hangul_builtin_keyboards[index_];
+ if (keyboard == NULL)
+ return NULL;
+
+ return keyboard->name;
+}
+
+static const HangulKeyboard*
+hangul_builtin_keyboard_list_get_keyboard(const char* id)
+{
+ size_t i;
+ for (i = 0; i < hangul_builtin_keyboard_count; ++i) {
+ const HangulKeyboard* keyboard = hangul_builtin_keyboards[i];
+ if (strcmp(id, keyboard->id) == 0) {
+ return keyboard;
+ }
+ }
+ return NULL;
+}
+
+unsigned int
+hangul_keyboard_list_get_count()
+{
+ if (hangul_builtin_keyboard_count > 0)
+ return hangul_builtin_keyboard_count;
+
+ return hangul_keyboards.n;
+}
+
+const char*
+hangul_keyboard_list_get_keyboard_id(unsigned index_)
+{
+ if (hangul_builtin_keyboard_count > 0) {
+ return hangul_builtin_keyboard_list_get_keyboard_id(index_);
+ }
+
+ if (index_ >= hangul_keyboards.n)
+ return NULL;
+
+ HangulKeyboard* keyboard = hangul_keyboards.keyboards[index_];
+ if (keyboard == NULL)
+ return NULL;
+
+ return keyboard->id;
+}
+
+const char*
+hangul_keyboard_list_get_keyboard_name(unsigned index_)
+{
+ if (hangul_builtin_keyboard_count > 0) {
+ return hangul_builtin_keyboard_list_get_keyboard_name(index_);
+ }
+
+ if (index_ >= hangul_keyboards.n)
+ return NULL;
+
+ HangulKeyboard* keyboard = hangul_keyboards.keyboards[index_];
+ if (keyboard == NULL)
+ return NULL;
+
+ return keyboard->name;
+}
+
+const HangulKeyboard*
+hangul_keyboard_list_get_keyboard(const char* id)
+{
+ if (hangul_builtin_keyboard_count > 0) {
+ return hangul_builtin_keyboard_list_get_keyboard(id);
+ }
+
+ size_t i;
+ for (i = 0; i < hangul_keyboards.n; ++i) {
+ HangulKeyboard* keyboard = hangul_keyboards.keyboards[i];
+ if (strcmp(id, keyboard->id) == 0) {
+ return keyboard;
+ }
+ }
+ return NULL;
+}
+
+static bool
+hangul_keyboard_list_append(HangulKeyboard* keyboard)
+{
+ if (hangul_keyboards.n >= hangul_keyboards.nalloced) {
+ size_t n = hangul_keyboards.nalloced * 2;
+ if (n == 0) {
+ n = 16;
+ }
+ HangulKeyboard** keyboards = hangul_keyboards.keyboards;
+ keyboards = realloc(keyboards, n * sizeof(keyboards[0]));
+ if (keyboards == NULL)
+ return false;
+
+ hangul_keyboards.nalloced = n;
+ hangul_keyboards.keyboards = keyboards;
+ }
+
+ size_t i = hangul_keyboards.n;
+ hangul_keyboards.keyboards[i] = keyboard;
+ hangul_keyboards.n = i + 1;
+
+ return true;
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 82fae4c..cb068dd 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,4 +2,6 @@
hangul/hangulctype.c
hangul/hangulinputcontext.c
+hangul/hangulkeyboard.c
hangul/hanja.c
+tools/hangul.c
diff --git a/test/hangul.c b/test/hangul.c
index 7f829a3..cbaf38f 100644
--- a/test/hangul.c
+++ b/test/hangul.c
@@ -67,6 +67,8 @@ main(int argc, char *argv[])
keyboard = argv[1];
}
+ hangul_init();
+
hic = hangul_ic_new(keyboard);
if (hic == NULL) {
printf("hic is null\n");
@@ -93,5 +95,7 @@ main(int argc, char *argv[])
hangul_ic_delete(hic);
+ hangul_fini();
+
return 0;
}
diff --git a/test/test.c b/test/test.c
index 1697720..3147ee5 100644
--- a/test/test.c
+++ b/test/test.c
@@ -528,18 +528,18 @@ START_TEST(test_hangul_keyboard)
unsigned int n;
unsigned int i;
- n = hangul_ic_get_n_keyboards();
+ n = hangul_keyboard_list_get_count();
fail_unless(n != 0,
- "error: there is no builtin hangul keyboard");
+ "error: there is no hangul keyboard");
for (i = 0; i < n; ++i) {
- id = hangul_ic_get_keyboard_id(i);
+ id = hangul_keyboard_list_get_keyboard_id(i);
fail_unless(id != NULL,
"error: keyboard id == NULL");
}
for (i = 0; i < n; ++i) {
- name = hangul_ic_get_keyboard_name(i);
+ name = hangul_keyboard_list_get_keyboard_name(i);
fail_unless(name != NULL,
"error: keyboard id == NULL");
}
@@ -582,6 +582,8 @@ Suite* libhangul_suite()
int main()
{
+ hangul_init();
+
int number_failed;
Suite* s = libhangul_suite();
SRunner* sr = srunner_create(s);
@@ -594,5 +596,7 @@ int main()
hangul_ic_delete(global_ic);
+ hangul_fini();
+
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tools/hangul.c b/tools/hangul.c
index bc6bba6..d2783c3 100644
--- a/tools/hangul.c
+++ b/tools/hangul.c
@@ -1,5 +1,5 @@
/* libhangul
- * Copyright (C) 2011 Choe Hwanjin
+ * Copyright (C) 2011 - 2016 Choe Hwanjin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -124,7 +124,7 @@ list_keyboards()
unsigned i;
unsigned n;
- n = hangul_ic_get_n_keyboards();
+ n = hangul_keyboard_list_get_count();
#if defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO)
if (n > 0) {
@@ -147,8 +147,8 @@ list_keyboards()
const char* id;
const char* name;
- id = hangul_ic_get_keyboard_id(i);
- name = hangul_ic_get_keyboard_name(i);
+ id = hangul_keyboard_list_get_keyboard_id(i);
+ name = hangul_keyboard_list_get_keyboard_name(i);
printf("%-12s %s\n", id, name);
}
@@ -310,6 +310,8 @@ main(int argc, char *argv[])
setlocale(LC_ALL, "");
+ hangul_init();
+
res = EXIT_SUCCESS;
keyboard = "2";
input_string = NULL;
@@ -406,6 +408,8 @@ main(int argc, char *argv[])
hangul_ic_delete(ic);
+ hangul_fini();
+
iconv_close(cd_ucs4_to_utf8);
if (strcmp(output_file, "-") != 0) {