Added support for composing 3x4 Korean language 99/84199/2
authorJi-hoon Lee <dalton.lee@samsung.com>
Thu, 11 Aug 2016 12:26:14 +0000 (21:26 +0900)
committerJihoon Kim <jihoon48.kim@samsung.com>
Wed, 17 Aug 2016 10:27:36 +0000 (19:27 +0900)
Change-Id: I810303e2ebbd08d87f8d8c11ee73e4a27fed7de7

CMakeLists.txt
data/layout/wearable/LYT_PORTRAIT_4X4_KOREAN.xml
src/include/languages.h
src/ise.cpp
src/languages.cpp
src/sdk/cji.cpp [new file with mode: 0644]
src/sdk/cji.h [new file with mode: 0644]
src/sdk/sdk.cpp

index 997aeb9..09684c6 100644 (file)
@@ -11,6 +11,7 @@ SET(ISE_SRCS
     src/ise-stt-mode.cpp
     src/ise-stt-option.cpp
     src/sdk/ise_lang_table.cpp
+    src/sdk/cji.cpp
     src/sdk/sdk.cpp
     src/sdk/sdk_option.cpp
     src/candidate/candidate-factory.cpp
index b377fde..ab7f2e6 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<layout width="360" height="240" magnifier="true" key_width="34" key_height="50" key_spacing="0" row_spacing="0" hit_left="0" hit_right="0" hit_top="0" hit_bottom="0" label_type="QTY_DEFAULT" vibe_style="DEFAULT" sound_style="DEFAULT">
+<layout width="360" height="240" magnifier="true" key_width="80" key_height="60" vibe_style="DEFAULT" sound_style="DEFAULT" label_type="3X4_DEFAULT">
   <image_path>
     <button_normal>B09_panel.png</button_normal>
   </image_path>
   <background_image>
-    <rec button="normal">button/B09_Qwerty_btn_01.png</rec>
-    <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-    <rec button="disabled">button/B09_Qwerty_btn_01.png</rec>
+    <rec button="pressed">key_btn_press.png</rec>
   </background_image>
-  <row x="10" y="0">
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="1" multitouch_type="settle_previous">
+  <row x="20">
+    <key key_type="user" long_key_value="1" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec shift="off" multi="0">ㅂ</rec>
-        <rec shift="on" multi="0">ㅃ</rec>
-        <rec shift="loc" multi="0">ㅃ</rec>
+        <rec multi="0" auto_upper="true">ㅣ</rec>
         <rec multi="1">1</rec>
       </label>
       <key_value>
-        <rec auto_upper="true">q</rec>
+        <rec auto_upper="true">SIPKEY_1</rec>
       </key_value>
     </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="2" multitouch_type="settle_previous">
+    <key key_type="user" long_key_value="2" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec shift="off" multi="0">ㅈ</rec>
-        <rec shift="on" multi="0">ㅉ</rec>
-        <rec shift="loc" multi="0">ㅉ</rec>
+        <rec multi="0" auto_upper="true">.</rec>
         <rec multi="1">2</rec>
       </label>
       <key_value>
-        <rec auto_upper="true">w</rec>
+        <rec auto_upper="true">SIPKEY_2</rec>
       </key_value>
     </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="3" multitouch_type="settle_previous">
+    <key key_type="user" long_key_value="3" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec shift="off" multi="0">ㄷ</rec>
-        <rec shift="on" multi="0">ㄸ</rec>
-        <rec shift="loc" multi="0">ㄸ</rec>
+        <rec multi="0" auto_upper="true">ㅡ</rec>
         <rec multi="1">3</rec>
       </label>
       <key_value>
-        <rec auto_upper="true">e</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="4" multitouch_type="settle_previous">
-      <label>
-        <rec shift="off" multi="0">ㄱ</rec>
-        <rec shift="on" multi="0">ㄲ</rec>
-        <rec shift="loc" multi="0">ㄲ</rec>
-        <rec multi="1">4</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">r</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="5" multitouch_type="settle_previous">
-      <label>
-        <rec shift="off" multi="0">ㅅ</rec>
-        <rec shift="on" multi="0">ㅆ</rec>
-        <rec shift="loc" multi="0">ㅆ</rec>
-        <rec multi="1">5</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">t</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="6" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅛ</rec>
-        <rec multi="1">6</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">y</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="7" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅕ</rec>
-        <rec multi="1">7</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">u</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="8" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅑ</rec>
-        <rec multi="1">8</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">i</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="9" multitouch_type="settle_previous">
-      <label>
-        <rec shift="off" multi="0">ㅐ</rec>
-        <rec shift="on" multi="0">ㅒ</rec>
-        <rec shift="loc" multi="0">ㅒ</rec>
-        <rec multi="1">9</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">o</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="0" multitouch_type="settle_previous" hit_right="8">
-      <label>
-        <rec shift="off" multi="0">ㅔ</rec>
-        <rec shift="on" multi="0">ㅖ</rec>
-        <rec shift="loc" multi="0">ㅖ</rec>
-        <rec multi="1">0</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">p</rec>
-      </key_value>
-    </key>
-  </row>
-  <row x="25">
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="-" multitouch_type="settle_previous" hit_left="36">
-      <label>
-        <rec multi="0">ㅁ</rec>
-        <rec multi="1">-</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">a</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="@" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㄴ</rec>
-        <rec multi="1">@</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">s</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="*" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅇ</rec>
-        <rec multi="1">*</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">d</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="^" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㄹ</rec>
-        <rec multi="1">^</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">f</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value=":" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅎ</rec>
-        <rec multi="1">:</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">g</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value=";" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅗ</rec>
-        <rec multi="1">;</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">h</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="(" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅓ</rec>
-        <rec multi="1">(</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">j</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value=")" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅏ</rec>
-        <rec multi="1">)</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">k</rec>
+        <rec auto_upper="true">SIPKEY_3</rec>
       </key_value>
     </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="~" multitouch_type="settle_previous" hit_right="35">
-      <label>
-        <rec multi="0">ㅣ</rec>
-        <rec multi="1">~</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">l</rec>
-      </key_value>
-    </key>
-  </row>
-  <row x="20">
-    <key long_key_value="LongShift" long_key_event="65505" button_type="selfish" key_type="control" width="40" hit_left="9">
+    <key key_type="control" use_repeat_key="true" image_label_type="IMAGE_3X4_TOP">
       <image_label>
-        <rec shift="off" button="normal">B09_icon_shift_off_54x54.png</rec>
-        <rec shift="on" button="normal">B09_icon_shift_on_54x54.png</rec>
-        <rec shift="loc" button="normal">B09_icon_shift_loc_54x54.png</rec>
-        <rec button="pressed">B09_icon_shift_press_54x54.png</rec>
-        <rec button="disabled">B09_icon_shift_dim_54x54.png</rec>
+        <rec button="normal">w_sip_3x4_btn_ic_delete.png</rec>
+        <rec button="pressed">w_sip_3x4_btn_ic_delete.png</rec>
       </image_label>
-      <background_image>
-        <rec shift="off" button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec shift="on" button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec shift="loc" button="normal">button/B09_Qwerty_btn_doubletab.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
-      <key_value>
-        <rec>Shift</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="/" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅋ</rec>
-        <rec multi="1">/</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">z</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="'" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅌ</rec>
-        <rec multi="1">'</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">x</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="&quot;" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅊ</rec>
-        <rec multi="1">"</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">c</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="." multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅍ</rec>
-        <rec multi="1">.</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">v</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="," multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅠ</rec>
-        <rec multi="1">,</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">b</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="?" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅜ</rec>
-        <rec multi="1">?</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">n</rec>
-      </key_value>
-    </key>
-    <key use_magnifier="true" longkey_magnifier="true" long_key_value="!" multitouch_type="settle_previous">
-      <label>
-        <rec multi="0">ㅡ</rec>
-        <rec multi="1">!</rec>
-      </label>
-      <key_value>
-        <rec auto_upper="true">m</rec>
-      </key_value>
-    </key>
-    <key button_type="selfish" key_type="control" use_magnifier="true" longkey_magnifier="true" use_repeat_key="true" width="40" hit_right="8">
-      <image_label>
-        <rec button="normal">B09_icon_back_nor_54x54.png</rec>
-        <rec button="pressed">B09_icon_back_press_54x54.png</rec>
-        <rec button="disabled">B09_icon_back_dim_54x54.png</rec>
-      </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
         <rec>BackSpace</rec>
       </key_value>
     </key>
   </row>
-  <row x="60" sub_layout="DEFAULT">
-    <key button_type="selfish" key_type="modechange" label_type="QTY_?123" width="40" hit_left="9">
+  <row x="20">
+    <key key_type="user" long_key_value="4" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec>?123</rec>
+        <rec multi="0" auto_upper="true">ㄱㅋ</rec>
+        <rec multi="1">4</rec>
       </label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
-        <rec>SYM_QTY_1</rec>
+        <rec auto_upper="true">SIPKEY_4</rec>
       </key_value>
     </key>
-    <key button_type="selfish" key_type="modechange" use_magnifier="false" custom_id="CM_KEY" label_type="SETTING_CUE" popup_type="longpress_popup_once" popup_offset_x="-12" popup_offset_y="-136">
+    <key key_type="user" long_key_value="5" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec>...</rec>
+        <rec multi="0" auto_upper="true">ㄴㄹ</rec>
+        <rec multi="1">5</rec>
       </label>
-      <image_label>
-        <rec button="normal">setting icon/B09_icon_setting_nor_54x54.png</rec>
-        <rec button="pressed">setting icon/B09_icon_setting_press_54x54.png</rec>
-        <rec button="disabled">setting icon/B09_icon_setting_dim_54x54.png</rec>
-      </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
-        <rec>OPTION</rec>
+        <rec auto_upper="true">SIPKEY_5</rec>
       </key_value>
-      <popup_input_mode_record>
-        <popup_input_mode>CM_POPUP</popup_input_mode>
-      </popup_input_mode_record>
     </key>
-    <key button_type="direction" key_type="control" label_type="QTY_SPACE" image_label_type="IMAGE_SPACE" width="100">
+    <key key_type="user" long_key_value="6" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec>_LANGUAGE_</rec>
+        <rec multi="0" auto_upper="true">ㄷㅌ</rec>
+        <rec multi="1">6</rec>
       </label>
-      <image_label>
-        <rec button="normal">B09_icon_space_nor_73x22.png</rec>
-        <rec button="pressed">B09_icon_space_press_73x22.png</rec>
-        <rec button="disabled">B09_icon_space_dim_73x22.png</rec>
-      </image_label>
       <key_value>
-        <rec>Space</rec>
+        <rec auto_upper="true">SIPKEY_6</rec>
       </key_value>
     </key>
-    <key popup_type="longpress_popup_once" label_type="QTY_DOT" image_label_type="IMAGE_CUE" popup_offset_x="-391" popup_offset_y="-254">
-      <label>
-        <rec>.</rec>
-      </label>
+    <key key_type="control" custom_id="Enter" image_label_type="IMAGE_3X4_TOP">
       <image_label>
-        <rec button="normal">B09_icon_question_45x30.png</rec>
-        <rec button="pressed">B09_icon_question_45x30.png</rec>
-        <rec button="disabled">B09_icon_question_45x30.png</rec>
+        <rec button="normal">w_sip_3x4_btn_ic_enter.png</rec>
+        <rec button="pressed">w_sip_3x4_btn_ic_enter.png</rec>
+        <rec button="disabled">w_sip_3x4_btn_ic_enter_d.png</rec>
       </image_label>
-      <popup_input_mode_record>
-        <popup_input_mode>PUNCTUATION_POPUP</popup_input_mode>
-      </popup_input_mode_record>
-    </key>
-    <key button_type="selfish" key_type="control" custom_id="Enter" label_type="QTY_?123" width="40" hit_right="8">
-      <image_label>
-        <rec button="normal">B09_icon_enter_nor_54x54.png</rec>
-        <rec button="pressed">B09_icon_enter_press_54x54.png</rec>
-        <rec button="disabled">B09_icon_enter_dim_54x54.png</rec>
-      </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
         <rec>Enter</rec>
       </key_value>
     </key>
   </row>
-  <row x="9" sub_layout="URL">
-    <key button_type="selfish" key_type="modechange" label_type="QTY_?123" width="100">
+  <row x="20">
+    <key key_type="user" long_key_value="7" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec>?123</rec>
+        <rec multi="0" auto_upper="true">ㅂㅍ</rec>
+        <rec multi="1">7</rec>
       </label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
-        <rec>SYM_QTY_1</rec>
+        <rec auto_upper="true">SIPKEY_7</rec>
       </key_value>
     </key>
-    <key button_type="selfish" key_type="modechange" use_magnifier="false" custom_id="CM_KEY" label_type="SETTING_CUE" popup_type="longpress_popup_once" popup_offset_x="-12" popup_offset_y="-136">
+    <key key_type="user" long_key_value="8" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec>...</rec>
+        <rec multi="0" auto_upper="true">ㅅㅎ</rec>
+        <rec multi="1">8</rec>
       </label>
-      <image_label>
-        <rec button="normal">setting icon/B09_icon_setting_nor_54x54.png</rec>
-        <rec button="pressed">setting icon/B09_icon_setting_press_54x54.png</rec>
-        <rec button="disabled">setting icon/B09_icon_setting_dim_54x54.png</rec>
-      </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
-        <rec>OPTION</rec>
+        <rec auto_upper="true">SIPKEY_8</rec>
       </key_value>
-      <popup_input_mode_record>
-        <popup_input_mode>CM_POPUP</popup_input_mode>
-      </popup_input_mode_record>
-    </key>
-    <key key_type="string" label_type="QTY_LINE1">
-      <label>
-        <rec>/</rec>
-      </label>
     </key>
-    <key button_type="direction" key_type="control" label_type="QTY_SPACE" image_label_type="IMAGE_SPACE" width="172">
+    <key key_type="user" long_key_value="9" long_key_type="string" longkey_magnifier="true">
       <label>
-        <rec>_LANGUAGE_</rec>
+        <rec multi="0" auto_upper="true">ㅈㅊ</rec>
+        <rec multi="1">9</rec>
       </label>
-      <image_label>
-        <rec button="normal">B09_icon_space_nor_73x22.png</rec>
-        <rec button="pressed">B09_icon_space_press_73x22.png</rec>
-        <rec button="disabled">B09_icon_space_dim_73x22.png</rec>
-      </image_label>
       <key_value>
-        <rec>Space</rec>
+        <rec auto_upper="true">SIPKEY_9</rec>
       </key_value>
     </key>
-    <key key_type="string" label_type="QTY_LINE1">
-      <label>
-        <rec>.</rec>
-      </label>
-    </key>
-    <key key_type="string" popup_type="longpress_popup_once" label_type="QTY_WWWCOM" popup_offset_x="-318" popup_offset_y="-230" width="100">
-      <label>
-        <rec>www.</rec>
-      </label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
-      <popup_input_mode_record>
-        <popup_input_mode>URL_POPUP</popup_input_mode>
-      </popup_input_mode_record>
-    </key>
-    <key button_type="selfish" key_type="control" custom_id="Enter" label_type="QTY_?123" width="100" hit_right="8">
+    <key key_type="control" image_label_type="IMAGE_3X4_TOP">
       <image_label>
-        <rec button="normal">B09_icon_enter_nor_54x54.png</rec>
-        <rec button="pressed">B09_icon_enter_press_54x54.png</rec>
-        <rec button="disabled">B09_icon_enter_dim_54x54.png</rec>
+        <rec shift="off" button="normal">w_sip_3x4_btn_ic_shift.png</rec>
+        <rec shift="on" button="normal">w_sip_3x4_btn_ic_shift.png</rec>
+        <rec shift="loc" button="normal">w_sip_3x4_btn_ic_shift_p.png</rec>
+        <rec button="pressed">w_sip_3x4_btn_ic_shift.png</rec>
+        <rec button="disabled">w_sip_3x4_btn_ic_shift_d.png</rec>
       </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
-        <rec>Enter</rec>
+        <rec>Shift</rec>
       </key_value>
     </key>
   </row>
-  <row x="9" sub_layout="EMAIL">
-    <key button_type="selfish" key_type="modechange" label_type="QTY_?123" width="100">
+  <row x="47">
+    <key key_type="user" long_key_value="0" long_key_type="string" longkey_magnifier="true" label_type="3X4_DEFAULT_0" width="133">
       <label>
-        <rec>?123</rec>
-      </label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
-      <key_value>
-        <rec>SYM_QTY_1</rec>
-      </key_value>
-    </key>
-    <key button_type="selfish" key_type="modechange" use_magnifier="false" custom_id="CM_KEY" label_type="SETTING_CUE" popup_type="longpress_popup_once" popup_offset_x="-12" popup_offset_y="-136">
-      <label>
-        <rec>...</rec>
+        <rec multi="0" auto_upper="true">ㅇㅁ</rec>
+        <rec multi="1">0</rec>
       </label>
-      <image_label>
-        <rec button="normal">setting icon/B09_icon_setting_nor_54x54.png</rec>
-        <rec button="pressed">setting icon/B09_icon_setting_press_54x54.png</rec>
-        <rec button="disabled">setting icon/B09_icon_setting_dim_54x54.png</rec>
-      </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
       <key_value>
-        <rec>OPTION</rec>
+        <rec auto_upper="true">SIPKEY_0</rec>
       </key_value>
-      <popup_input_mode_record>
-        <popup_input_mode>CM_POPUP</popup_input_mode>
-      </popup_input_mode_record>
-    </key>
-    <key key_type="string" label_type="QTY_LINE1">
-      <label>
-        <rec>@</rec>
-      </label>
     </key>
-    <key button_type="direction" key_type="control" label_type="QTY_SPACE" image_label_type="IMAGE_SPACE" width="172">
+    <key button_type="direction" key_type="control" label_type="3X4_DEFAULT_SPACE" image_label_type="IMAGE_3X4_SPACE" width="133">
       <label>
         <rec>_LANGUAGE_</rec>
       </label>
       <image_label>
-        <rec button="normal">B09_icon_space_nor_73x22.png</rec>
-        <rec button="pressed">B09_icon_space_press_73x22.png</rec>
-        <rec button="disabled">B09_icon_space_dim_73x22.png</rec>
+        <rec button="normal">w_sip_3x4_btn_ic_space.png</rec>
+        <rec button="pressed">w_sip_3x4_btn_ic_space.png</rec>
       </image_label>
       <key_value>
         <rec>Space</rec>
       </key_value>
     </key>
-    <key key_type="string" label_type="QTY_LINE1">
-      <label>
-        <rec>.</rec>
-      </label>
-    </key>
-    <key key_type="string" popup_type="longpress_popup_once" label_type="QTY_WWWCOM" popup_offset_x="-318" popup_offset_y="-230" width="100">
-      <label>
-        <rec>.com</rec>
-      </label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
-      <popup_input_mode_record>
-        <popup_input_mode>URL_POPUP</popup_input_mode>
-      </popup_input_mode_record>
-    </key>
-    <key button_type="selfish" key_type="control" custom_id="Enter" label_type="QTY_?123" width="100">
-      <image_label>
-        <rec button="normal">B09_icon_enter_nor_54x54.png</rec>
-        <rec button="pressed">B09_icon_enter_press_54x54.png</rec>
-        <rec button="disabled">B09_icon_enter_dim_54x54.png</rec>
-      </image_label>
-      <background_image>
-        <rec button="normal">button/B09_Qwerty_btn_02.png</rec>
-        <rec button="pressed">button/B09_Qwerty_btn_press.png</rec>
-        <rec button="disabled">button/B09_Qwerty_btn_02.png</rec>
-      </background_image>
-      <key_value>
-        <rec>Enter</rec>
-      </key_value>
-    </key>
   </row>
 </layout>
index 1f05db8..8c38880 100644 (file)
@@ -41,6 +41,8 @@ struct ILanguageCallback : public ISCLUIEventCallback {
     virtual sclboolean on_language_selected(const sclchar *language, const sclchar *input_mode) { return FALSE; }
     /* Additional callback function, which is called when this language is unselected */
     virtual sclboolean on_language_unselected(const sclchar *language, const sclchar *input_mode) { return FALSE; }
+
+    virtual sclboolean reset_language(const sclchar *language) { return FALSE; }
 };
 
 struct INPUT_MODE_INFO {
@@ -101,6 +103,8 @@ public:
     sclboolean select_next_language();
     sclboolean select_previous_language();
 
+    sclboolean reset_language(const sclchar *name);
+
     sclboolean set_language_enabled(const sclchar *name, sclboolean enabled);
     sclboolean set_language_enabled_temporarily(const sclchar *name, sclboolean enabled_temporarily);
     /* if languages num is 0, enable default language, othewise enable languages assigned */
index b8d6703..3ee4390 100644 (file)
@@ -634,6 +634,7 @@ void CCoreEventCallback::on_process_input_device_event(sclu32 &type, sclchar *da
                 g_keyboard_state.layout = new_layout;
 
                 if (g_keyboard_state.visible_state) {
+                    _language_manager.reset_language(g_config_values.selected_language.c_str());
                     ise_show(g_keyboard_state.ic);
                 }
 
@@ -1080,6 +1081,7 @@ ise_reset_context()
 {
     LOGD("");
     _reset_multitap_state();
+    _language_manager.reset_language(g_config_values.selected_language.c_str());
 }
 
 void
@@ -1088,6 +1090,7 @@ ise_reset_input_context()
     LOGD("");
     _reset_multitap_state();
     g_keyboard_state.disable_force_latin = FALSE;
+    _language_manager.reset_language(g_config_values.selected_language.c_str());
 }
 
 void
@@ -1356,6 +1359,8 @@ ise_set_accessibility_state(bool state)
 void
 ise_hide()
 {
+    _language_manager.reset_language(g_config_values.selected_language.c_str());
+
     _click_count = 0;
     delete_commit_timer();
 
index 01ed490..8f9ea14 100644 (file)
@@ -290,6 +290,39 @@ ISELanguageManager::select_previous_language()
     return ret;
 }
 
+sclboolean
+ISELanguageManager::reset_language(const sclchar *name)
+{
+    sclboolean ret = FALSE;
+
+    if (name == NULL) return FALSE;
+    int pos = _find_language_info(name, _language_vector);
+
+    // the assigned language could not be found in the language info vector
+    if (pos < 0 || pos >= (int)_language_vector.size()) {
+        return FALSE;
+    }
+
+    // if the language is not the one currently selected
+    if (pos != _current_language) {
+        return FALSE;
+    }
+
+    LANGUAGE_INFO &language_info = _language_vector.at(pos);
+    // if not enabled and not temporary, return false
+    if (!language_info.enabled && !language_info.enabled_temporarily) {
+        return FALSE;
+    }
+
+    // run the callback function
+    ILanguageCallback *callback = language_info.callback;
+    if (callback) {
+        ret = callback->reset_language(get_current_language());
+    }
+
+    return ret;
+}
+
 sclboolean ISELanguageManager::set_language_enabled(const sclchar *name, sclboolean enabled)
 {
     sclboolean ret = FALSE;
diff --git a/src/sdk/cji.cpp b/src/sdk/cji.cpp
new file mode 100644 (file)
index 0000000..88aaa33
--- /dev/null
@@ -0,0 +1,1786 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "cji.h"
+
+static int current_state = EMPTY_STATE;
+static int current_state_backup = EMPTY_STATE;
+
+static MAKECODE g_makecode;
+static MAKECODE g_makecode_backup;
+
+static AUTOMATA_HISTORY_INFO g_AH_Stack[MAX_AUTOMATA_HISTORY_LENGTH]; // Automata History Stack
+static AUTOMATA_HISTORY_INFO g_AH_Stack_backup[MAX_AUTOMATA_HISTORY_LENGTH]; // Automata History Stack
+
+static int g_AH_Stack_ptr=0;
+static int g_AH_Stack_ptr_backup=0;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+int process3X4RotationKey(int p_SIPKey)
+{
+    static int p_LastSIPKey = SIPKEY_ERROR;
+
+    int loop;
+    int p_ResultSIPKey = SIPKEY_ERROR;
+
+    if (p_SIPKey >= SIPKEY_3X4_KEY_START && p_SIPKey <= SIPKEY_3X4_KEY_END) {
+        int i3X4Index = p_SIPKey - SIPKEY_3X4_KEY_START;
+        for (loop = 0;loop < SIPKEY_3X4_KEY_ROTATION_CANIDATE_NUM &&
+                p_ResultSIPKey == SIPKEY_ERROR;loop++) {
+            if (SIPKEY3X4RotationTable[i3X4Index][loop] == p_LastSIPKey) {
+                loop++;
+                if (loop >= SIPKEY_3X4_KEY_ROTATION_CANIDATE_NUM) {
+                    loop = 0;
+                }
+                if (SIPKEY3X4RotationTable[i3X4Index][loop] == SIPKEY_ERROR) {
+                    loop = 0;
+                }
+
+                p_ResultSIPKey = SIPKEY3X4RotationTable[i3X4Index][loop];
+            }
+        }
+
+        if (p_ResultSIPKey == SIPKEY_ERROR) {
+            p_ResultSIPKey = SIPKEY3X4RotationTable[i3X4Index][0];
+        }
+    } else {
+        p_ResultSIPKey = p_SIPKey;
+    }
+
+    p_LastSIPKey = p_ResultSIPKey;
+
+    return p_ResultSIPKey;
+}
+
+MAKECODE CJI_GetMakeCode()
+{
+    return g_makecode;
+}
+
+/**
+* 한글 조합을 처리하는 오토 마타이다.
+* - 입력
+*              p_isJAEUM : TRUE 자음, FALSE 모음
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+*              current_state : CURRENT_STATE를 입력으로 받아 ACTION 수행후 NEXT_STATE를 Setting 한다.
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+* return value : TRUE : 오토마타가 적절하게 수행됨 (legal case), FALSE : 오토마타가 적절하게 수행되지 못함 - 예외상황처리 (illegal case)
+*/
+int CJI_Automata(int p_isJAEUM, short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(current_state >= EMPTY_STATE && current_state <= NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE);      //정의된 스테이트 값들을 가져야 한다.
+    ASSERT((p_isJAEUM == TRUE && (p_SIPKey >= 0 || p_SIPKey < SIPKEY_TABLE_SIZE) ||                                    //자음일 경우 자음 테이블 인덱스 안에 있어야 한다.
+            (p_isJAEUM == FALSE && (p_SIPKey >= 0 || p_SIPKey < 3));                                                                   //모음일 경우 천(0) 지(1) 인(2) 만을 사용한다.
+#endif // CJI_DEBUG
+
+    static int p_LastSIPKey = SIPKEY_ERROR;
+    bool b3X4KeyRotated = FALSE;
+    if (p_isJAEUM) {
+    int p_RotatedSIPKey = process3X4RotationKey(p_SIPKey);
+        if (p_RotatedSIPKey != p_SIPKey) {
+            if (p_SIPKey == p_LastSIPKey) {
+                b3X4KeyRotated = TRUE;
+                if (current_state != EMPTY_STATE) {
+                    popFromAutomataHistoryStack();
+                }
+            }
+            p_LastSIPKey = p_SIPKey;
+            p_SIPKey = p_RotatedSIPKey;
+        } else {
+            p_LastSIPKey = p_SIPKey;
+        }
+    } else {
+        process3X4RotationKey(SIPKEY_ERROR);
+        p_LastSIPKey = SIPKEY_ERROR;
+    }
+
+    if(p_SIPKey == (short)SIPKEY_ERROR) {
+        return ACTION_ERROR_KEY(p_SIPKey, p_madecode);
+    }
+    if(p_SIPKey == (short)SIPKEY_BACKSPACE) {
+        return ACTION_BACKSPACE_KEY(p_SIPKey, p_madecode);
+    }
+
+    /* Automata History Stack */
+    if (current_state != EMPTY_STATE)
+    pushEnvToAutomataHistoryStack(current_state, g_makecode);  //현재 오토마타 환경을 Stack에 저장하고 Next State로 이동한다.
+
+    switch (current_state) {
+
+    case EMPTY_STATE :                                                                                                 //current_State 가 EMPTY_STATE 일 경우
+        if (p_isJAEUM == TRUE) {                                                                                       //입력문자가 자음이면
+                current_state = CHO_STATE;                                                             //NEXT_STATE로 CHO_STATE를 Setting
+                ACTION_EMPTY_2_CHO(p_SIPKey, p_madecode);                                      //EMPTY_STATE에서 CHO_STATE로 가는 ACTION 수행
+                return TRUE;
+            } else {                                                                                                           //입력문자가 모음이면
+                current_state = NOCHO_JUNG_ERROR_STATE;
+                ACTION_ERROR_EMPTY_2_NOCHO_JUNG(p_SIPKey, p_madecode);         //ERROR 처리
+                return TRUE;
+            }
+            break;
+
+        case CHO_STATE :                                                                                                       //current_State 가 CHO_STATE 일 경우
+            if (p_isJAEUM == TRUE) {                                                                                   //입력문자가 자음이면
+                int djong_idx = getJONGIndexofDJONG_withCHOandSIPKEY(g_makecode.cho_idx, p_SIPKey);    //조합된 종성의 인덱스를 가져온다.
+                if (djong_idx == COMBINATION_FAIL) {                                                                                                   //종성조합불가자음이면
+                    current_state = CHO_STATE;                                                                                                 //NEXT_STATE로 CHO_STATE Setting
+                    ACTION_ERROR_CHO_2_CHO(p_SIPKey, p_madecode);                                                                      //ERROR 처리
+                    return TRUE;
+                } else {                                                                                                                               //종성조합가능자음
+                    current_state = NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE;                               //NEXT_STATE로 NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE Setting
+                    ACTION_ERROR_CHO_2_NOCHO_NOJUNG_DOUBLEJONG(djong_idx, p_madecode); //ERROR 처리
+                    return TRUE;
+                }
+
+            } else {                                                                                                                           //입력문자가 모음이면
+                current_state = CHO_JUNG_STATE;                                                                        //NEXT_STATE로 CHO_JUNG_STATE Setting
+                ACTION_CHO_2_CHO_JUNG(p_SIPKey, p_madecode);                                           //CHO_STATE에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                return TRUE;
+            }
+            break;
+
+        case CHO_JUNG_STATE :                                                                                                          //current_State 가 CHO_JUNG_STATE 일 경우
+            if (p_isJAEUM == TRUE) {                                                                                                   //입력문자가 자음이면
+                if (g_makecode.jung_idx < 2) {                                                                         //조합중인 모음이 '.', '..'이면
+                    current_state = CHO_STATE;
+                    ACTION_ERROR_CHO_JUNG_2_CHO(p_SIPKey, p_madecode);                         //ERROR 처리
+                    return TRUE;
+                } else if (CANTJONGTable[p_SIPKey] == FALSE) {                                         //종성불가자음 자음이면
+                    if (b3X4KeyRotated) {
+                        current_state = CHO_JUNG_CHO_STATE;                                                                    //NEXT_STATE로 CHO_STATE Setting
+                        ACTION_CHO_JUNG_2_CHO_JUNG_CHO(p_SIPKey, p_madecode);                                  //CHO_JUNG_STATE에서 CHO_STATE로 가는 ACTION 수행
+                    } else {
+                        current_state = CHO_STATE;                                                                     //NEXT_STATE로 CHO_STATE Setting
+                        ACTION_CHO_JUNG_2_CHO(p_SIPKey, p_madecode);                                   //CHO_JUNG_STATE에서 CHO_STATE로 가는 ACTION 수행
+                    }
+                    return TRUE;
+                } else {                                                                                                                       //종성불가 자음이 아니면
+                    current_state = CHO_JUNG_SINGLEJONG_STATE;                                 //NEXT_STATE로 CHO_JUNG_SINGLEJONG Setting
+                    ACTION_CHO_JUNG_2_CHO_JUNG_SINGLEJONG(p_SIPKey, p_madecode);       //CHO_JUNG_STATE에서 CHO_JUNG_SINGLEJONG로 가는 ACTION 수행
+                    return TRUE;
+                }
+
+            } else {                                                                                                           //입력문자가 모음이면
+                int idx = MOEUMAutomata[g_makecode.jung_idx][p_SIPKey];                //모음 오토마타를 이용해 조합된 모음의 중성 Index를 얻는다.
+                if (idx == COMBINATION_FAIL) { //중성조합불가모음
+                    /* 모음 조합이 안되는 경우 입력을 받지 않도록 변경.*/
+                    /* 단 'ㅓ','ㅗ'후에 '.'이 들어온 경우에는 예외처리를 해준다. */
+                    if (g_makecode.jung_idx == U_MOEUM_AUTOMATA_INDEX && p_SIPKey == SIPKEY_IDX0) { /* ㅓ */
+                        current_state = CHO_JUNG_STATE;                                                                //NEXT_STATE로 CHO_JUNG_STATE Setting
+                        ACTION_CHO_JUNG_2_CHO_JUNG(p_SIPKey, YEO_MOEUM_AUTOMATA_INDEX, p_madecode);                    //CHO_JUNG_STATE에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                        return TRUE;
+                    } else if (g_makecode.jung_idx == O_MOEUM_AUTOMATA_INDEX && p_SIPKey == SIPKEY_IDX0) { /* ㅗ */
+                        current_state = CHO_JUNG_STATE;                                                                //NEXT_STATE로 CHO_JUNG_STATE Setting
+                        ACTION_CHO_JUNG_2_CHO_JUNG(p_SIPKey, YO_MOEUM_AUTOMATA_INDEX, p_madecode);                     //CHO_JUNG_STATE에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                        return TRUE;
+                    } else {
+                        //popFromAutomataHistoryStack();
+                        current_state = NOCHO_JUNG_ERROR_STATE;
+                        ACTION_ERROR_CHO_JUNG_2_NOCHO_JUNG(p_SIPKey, p_madecode);              //ERROR 처리
+                        return FALSE;
+                    }
+
+                } else { //중성조합가능모음
+                    current_state = CHO_JUNG_STATE;                                                            //NEXT_STATE로 CHO_JUNG_STATE Setting
+                    ACTION_CHO_JUNG_2_CHO_JUNG(p_SIPKey, idx, p_madecode);                     //CHO_JUNG_STATE에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                    return TRUE;
+                }
+            }
+            break;
+
+        case CHO_JUNG_CHO_STATE :                                                                                                              //current_State 가 CHO_JUNG_CHO_STATE 일 경우
+            if (p_isJAEUM == TRUE) {                                                                                   //입력문자가 자음이면
+                current_state = CHO_STATE;                                                                     //NEXT_STATE로 CHO_STATE Setting
+                ACTION_CHO_JUNG_CHO_2_CHO(p_SIPKey, p_madecode);
+            } else {                                                                                                                           //입력문자가 모음이면
+                current_state = CHO_JUNG_STATE;                                                                        //NEXT_STATE로 CHO_JUNG_STATE Setting
+                ACTION_CHO_JUNG_CHO_2_CHO_JUNG(p_SIPKey, p_madecode);                                          //CHO_STATE에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                return TRUE;
+            }
+            break;
+        case CHO_JUNG_SINGLEJONG_CHO_STATE :                                                                                                           //current_State 가 CHO_JUNG_CHO_STATE 일 경우
+            if (p_isJAEUM == TRUE) {                                                                                   //입력문자가 자음이면
+                current_state = CHO_STATE;                                                                     //NEXT_STATE로 CHO_STATE Setting
+                ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO(p_SIPKey, p_madecode);
+            } else {                                                                                                                           //입력문자가 모음이면
+                current_state = CHO_JUNG_STATE;                                                                        //NEXT_STATE로 CHO_JUNG_STATE Setting
+                ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO_JUNG(p_SIPKey, p_madecode);                                               //CHO_STATE에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                return TRUE;
+            }
+            break;
+
+
+        case CHO_JUNG_SINGLEJONG_STATE :                                                                                       //current_State 가 CHO_JUNG_SINGLEJONG_STATE 일 경우
+            if (p_isJAEUM == TRUE) {                                                                                                   //입력문자가 자음이면
+                int djong_idx = getJONGIndexofDJONG_withJONGandSIPKEY(g_makecode.jong_idx, p_SIPKey);          //조합된 종성의 인덱스를 가져온다.
+                if (djong_idx == COMBINATION_FAIL) {                                                           //종성조합불가자음이면
+                    if (getRotationKeyCanBeDOUBLEJONG(g_makecode.jong_idx, p_LastSIPKey)) {
+                        current_state = CHO_JUNG_SINGLEJONG_CHO_STATE;                                                         //NEXT_STATE로 CHO_STATE Setting
+                        ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_SINGLEJONG_CHO(p_SIPKey, p_madecode);            //CHO_JUNG_SINGLEJONG_STATE 에서 CHO_STATE로 가는 ACTION 수행
+                        return TRUE;
+                    }
+                    current_state = CHO_STATE;                                                         //NEXT_STATE로 CHO_STATE Setting
+                    ACTION_CHO_JUNG_SINGLEJONG_2_CHO(p_SIPKey, p_madecode);            //CHO_JUNG_SINGLEJONG_STATE 에서 CHO_STATE로 가는 ACTION 수행
+                    return TRUE;
+                } else {                                                                                                                                       //종성조합가능자음
+                    current_state = CHO_JUNG_DOUBLEJONG_STATE;                                                 //NEXT_STATE로 CHO_JUNG_DOUBLEJONG Setting
+                    ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_DOUBLEJONG(djong_idx, p_madecode); //CHO_JUNG_SINGLEJONG_STATE 에서 CHO_JUNG_DOUBLEJONG로 가는 ACTION 수행
+                    return TRUE;
+                }
+            } else {                                                                                                                           //입력문자가 모음이면
+                current_state = CHO_JUNG_STATE;                                                                //NEXT_STATE로 CHO_JUNG_STATE Setting
+                ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG(p_SIPKey, p_madecode);   //CHO_JUNG_SINGLEJONG에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                return TRUE;
+            }
+            break;
+
+        case CHO_JUNG_DOUBLEJONG_STATE :                                                                                       //current_State 가 CHO_JUNG_SINGLEJONG_STATE 일 경우
+            if (p_isJAEUM == TRUE) {                                                                                                   //입력문자가 자음이면
+                current_state = CHO_STATE;                                                                     //NEXT_STATE로 CHO_STATE Setting
+                ACTION_CHO_JUNG_DOUBLEJONG_2_CHO(p_SIPKey, p_madecode);                        //CHO_JUNG_DOUBLEJONG_STATE 에서 CHO_STATE로 가는 ACTION 수행
+                return TRUE;
+            } else {                                                                                                                           //입력문자가 모음이면
+                current_state = CHO_JUNG_STATE;                                                                //NEXT_STATE로 CHO_JUNG_STATE Setting
+                ACTION_CHO_JUNG_DOUBLEJONG_2_CHO_JUNG(p_SIPKey, p_madecode);   //CHO_JUNG_DOUBLEJONG에서 CHO_JUNG_STATE로 가는 ACTION 수행
+                return TRUE;
+            }
+            break;
+
+
+        case NOCHO_JUNG_ERROR_STATE :
+            if (p_isJAEUM == TRUE) {                                                                                   //입력문자가 자음이면
+                current_state = CHO_STATE;                                                             //NEXT_STATE로 CHO_STATE Setting
+                ACTION_ERROR_NOCHO_JUNG_2_CHO(p_SIPKey, p_madecode);           //ERROR 처리
+                return TRUE;
+            } else {                                                                                                           //입력문자가 모음이면
+                int idx = MOEUMAutomata[g_makecode.jung_idx][p_SIPKey];                //모음 오토마타를 이용해 조합된 모음의 중성 Index를 얻는다.
+                if (idx == COMBINATION_FAIL) { //중성조합불가모음
+                    current_state = NOCHO_JUNG_ERROR_STATE;
+                    ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_NO(p_SIPKey, p_madecode);         //ERROR 처리
+                    return TRUE;
+                } else { //중성조합가능모음
+                    current_state = NOCHO_JUNG_ERROR_STATE;
+                    ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_OK(p_SIPKey, idx, p_madecode);            //ERROR 처리
+                    return TRUE;
+                }
+            }
+            break;
+
+
+        case NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE :
+            if (p_isJAEUM == TRUE) {                                                                                                                   //입력문자가 자음이면
+                current_state = CHO_STATE;                                                                                     //NEXT_STATE로 CHO_STATE Setting
+                ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO(p_SIPKey, p_madecode);              //ERROR 처리
+                return TRUE;
+            } else {                                                                                                                                           //입력문자가 모음이면
+                current_state = CHO_JUNG_STATE;                                                                                //NEXT_STATE로 CHO_JUNG_STATE Setting
+                ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO_JUNG(p_SIPKey, p_madecode);  //ERROR 처리
+                return TRUE;
+            }
+            break;
+
+        default :
+            break;
+        }
+
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+#endif // CJI_DEBUG
+
+    return FALSE;
+}
+
+#include <memory.h>
+void Backup_Automata()
+{
+    current_state_backup = current_state;
+    g_makecode_backup = g_makecode;
+    memcpy(g_AH_Stack_backup, g_AH_Stack, sizeof(g_AH_Stack_backup));
+    g_AH_Stack_ptr_backup = g_AH_Stack_ptr;
+}
+void Restore_Automata()
+{
+    current_state = current_state_backup;
+    g_makecode = g_makecode_backup;
+    memcpy(g_AH_Stack, g_AH_Stack_backup, sizeof(g_AH_Stack));
+    g_AH_Stack_ptr = g_AH_Stack_ptr_backup;
+}
+
+/**
+* ACTION_EMPTY_2_CHO : EMPTY_STATE에서 CHO_STATE로 갈때 처리
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_EMPTY_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                             //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                               //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+
+/**
+* ACTION_CHO_2_CHO_JUNG : CHO_STATE에서 CHO_JUNG_STATE로 갈때 처리
+* - 입력
+*              p_SIPKey : 모음 - 천 0, 지 1, 인 2
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);     //천지인만 허용
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                //입력문자를 중성으로 사용
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    if (p_SIPKey == CHUN_MOEUM_AUTOMATA_INDEX) {       // "." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                           //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                         //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_SIPKey];                                                                                      //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                           //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);         //조합중인 글자의 유니코드
+    }
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+
+/**
+* ACTION_CHO_JUNG_2_CHO_JUNG : CHO_JUNG_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 모음이 계속 조합될 때
+* - 입력
+*              p_jung_idx : 중성테이블에서의 인덱스
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_2_CHO_JUNG(short p_SIPKey, short p_jung_idx, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_jung_idx >= 0 && p_jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+    short prev_jung_idx;
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    prev_jung_idx = g_makecode.jung_idx;                               //이전키의 중성 인덱스를 저장
+    g_makecode.jung_idx = p_jung_idx;                                                                                                                          //중성인덱스
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    if (p_jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || p_jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)       {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                           //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                         //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_jung_idx];                                                                                    //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                           //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);         //조합중인 글자의 유니코드
+    }
+
+    /* Automata History Stack */
+    /* ".." -> ".", "ㅑ"->"ㅏ', "ㅠ"->"ㅜ" 로 토글되는 경우에는 이전 상태를 Stack에서 제거 한다.
+    * "..", "ㅑ", "ㅠ" 를 " ", "ㅣ", "ㅡ" 상태로 만들어 주며 Next SIP 입력으로 현재 Env 저장시 "."이 Stack에 push되어 ".", "ㅏ", "ㅜ"로 복원
+    */
+    if (       ( prev_jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX || prev_jung_idx == I_MOEUM_AUTOMATA_INDEX || prev_jung_idx == B_MOEUM_AUTOMATA_INDEX ) &&
+    (p_SIPKey == SIPKEY_IDX0) ) {
+        popFromAutomataHistoryStack();
+        popFromAutomataHistoryStack();
+    }
+
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_2_CHO : CHO_JUNG_STATE에서 CHO_STATE로 갈때 처리 - 종성불가자음 이 올 때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 1;                                                                                                                                                      //조합 완료 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);                    //조합 완료 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_2_CHO_JUNG_SINGLEJONG : CHO_JUNG_STATE에서 CHO_JUNG_SINGLEJONG_STATE로 갈때 처리 - 종성으로 단일자음 사용
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_2_CHO_JUNG_SINGLEJONG(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.jong_idx = SIPKEY2JONGTable[p_SIPKey];                                                                                          //입력문자를 종성으로 사용
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);           //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+bool ACTION_ERROR_KEY(short p_SIPKey, MADECODE *p_madecode)
+{
+    bool ret = FALSE;
+    if(current_state != EMPTY_STATE) {
+        ret = TRUE;
+    }
+    p_madecode->size = g_makecode.size;
+    p_madecode->ucode[0] = g_makecode.ucode[0];
+    p_madecode->ucode[1] = g_makecode.ucode[1];
+
+    initAutomataEnv();
+
+    return ret;
+}
+
+bool ACTION_BACKSPACE_KEY(short p_SIPKey, MADECODE *p_madecode)
+{
+    switch(current_state) {
+        case EMPTY_STATE:
+            {
+                return FALSE;
+            }
+        break;
+        case CHO_STATE:
+        case CHO_JUNG_SINGLEJONG_STATE:
+        case CHO_JUNG_DOUBLEJONG_STATE:
+        case NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE:
+        case CHO_JUNG_CHO_STATE:
+        case CHO_JUNG_SINGLEJONG_CHO_STATE:
+            {
+                int oldState = current_state;
+                do
+                {
+                    popFromAutomataHistoryStack();
+                } while (current_state == oldState && current_state != EMPTY_STATE);
+            }
+            break;
+        case CHO_JUNG_STATE:
+        case NOCHO_JUNG_ERROR_STATE:
+            {
+                if(BS_MOEUMInfo_Automata[g_makecode.jung_idx] != EMPTY_CODE) {
+                    g_makecode.jung_idx = BS_MOEUMInfo_Automata[g_makecode.jung_idx];
+                    g_makecode.size = 1;                                                                                                                                               //조합중인 코드 사이즈 1
+                    if(current_state == CHO_JUNG_STATE) {
+                        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);         //조합중인 글자의 유니코드
+                    } else { /* NOCHO_JUNG_ERROR_STATE */
+                        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE;  //조합중인 글자의 유니코드
+                    }
+                } else {
+                    int oldState = current_state;
+                    do
+                    {
+                        popFromAutomataHistoryStack();
+                    } while (current_state == oldState && current_state != EMPTY_STATE);
+                }
+            }
+            break;
+    }
+
+    return TRUE;
+}
+
+/**
+* ACTION_CHO_JUNG_2_CHO_JUNG_CHO : CHO_JUNG_STATE에서 CHO_JUNG_CHO_STATE로 갈때 처리 - 초성 입력이지만 조합 완료시키지 않음
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_2_CHO_JUNG_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.next_cho_idx = p_SIPKey;                                                                                                //입력문자를 종성으로 사용
+    g_makecode.size = 2;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);             //조합중인 글자의 유니코드
+    g_makecode.ucode[1] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.next_cho_idx]];                //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_CHO_2_CHO : CHO_JUNG_CHO_STATE에서 CHO_STATE로 갈때 처리 - 조합 완료후 새로운 조합 시작
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_CHO_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 2;                                                                                                                                                      //조합 완료 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);                    //조합 완료 글자의 유니코드
+    p_madecode->ucode[1] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.next_cho_idx]];                                       //조합중인 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+}
+
+/**
+* ACTION_CHO_JUNG_CHO_2_CHO_JUNG : CHO_JUNG_CHO_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 조합 완료후 새로운 조합 시작
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_CHO_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 1;                                                                                                                                                      //조합 완료 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);                    //조합 완료 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = g_makecode.next_cho_idx;                                                                                                                                      //입력문자를 초성으로 사용
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용                                   //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                           //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                         //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_SIPKey];                                                                                      //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                           //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);         //조합중인 글자의 유니코드
+    }
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+}
+
+
+/**
+* ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_SINGLEJONG_CHO : CHO_JUNG_SINGLEJONG_STATE에서 CHO_JUNG_SINGLEJONG_CHO_STATE로 갈때 처리 - 초성 입력이지만 조합 완료시키지 않음
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_SINGLEJONG_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.next_cho_idx = p_SIPKey;                                                                                                //입력문자를 종성으로 사용
+    g_makecode.size = 2;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);           //조합중인 글자의 유니코드
+    g_makecode.ucode[1] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.next_cho_idx]];                //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+
+/**
+* ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO : CHO_JUNG_SINGLEJONG_CHO_STATE에서 CHO_STATE로 갈때 처리 - 조합 완료후 새로운 조합 시작
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 2;                                                                                                                                                      //조합 완료 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);                  //조합 완료 글자의 유니코드
+    p_madecode->ucode[1] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.next_cho_idx]];                                       //조합중인 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+}
+
+/**
+* ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO_JUNG : CHO_JUNG_SINGLEJONG_CHO_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 조합 완료후 새로운 조합 시작
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 1;                                                                                                                                                      //조합 완료 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);                  //조합 완료 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = g_makecode.next_cho_idx;                                                                                                                                      //입력문자를 초성으로 사용
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용                                   //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                           //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                         //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_SIPKey];                                                                                      //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                           //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);         //조합중인 글자의 유니코드
+    }
+
+    /* 완료글자의 종성문자를 조합중인 문자의 초성으로 Automata History Stack에 Push 한다. */
+    int TMPstate = CHO_STATE;
+    MAKECODE TMPcode;
+    TMPcode.cho_idx = g_makecode.cho_idx;
+    TMPcode.size = 1;
+    TMPcode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];
+    pushEnvToAutomataHistoryStack(TMPstate, TMPcode);  //초성의 오토마타 환경을 저장
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+}
+
+/**
+* ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG : CHO_JUNG_SINGLEJONG_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 종성이 나온 상태에서 모음이 나올 때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);   //천지인
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 1;                                                                                                                                      //조합 완료 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);    //조합 완료 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = JONG2CHOTable[g_makecode.jong_idx];                                                                                   //조합중인 글자의 종성을 초성으로 사용
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    if (p_SIPKey == CHUN_MOEUM_AUTOMATA_INDEX) {       // "." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                                   //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                 //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_SIPKey];                                                                                              //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);                 //조합중인 글자의 유니코드
+    }
+
+
+    /* Automata History Stack */
+    /* 완료글자의 종성문자를 조합중인 문자의 초성으로 Automata History Stack에 Push 한다. */
+    int TMPstate = CHO_STATE;
+    MAKECODE TMPcode;
+    TMPcode.cho_idx = g_makecode.cho_idx;
+    TMPcode.size = 1;
+    TMPcode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];
+    pushEnvToAutomataHistoryStack(TMPstate, TMPcode);  //초성의 오토마타 환경을 저장
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_SINGLEJONG_2_CHO : CHO_JUNG_SINGLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 종성조합불가자음이 나올때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_SINGLEJONG_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 1;
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);  //조합완료된 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_DOUBLEJONG : CHO_JUNG_SINGLEJONG_STATE에서 CHO_JUNG_DOUBLEJONG_STATE로 갈때 처리 - 종성조합가능자음이 나올때
+* - 입력
+*              p_djong_idx : 조합된 이중자음의 index
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+void ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_DOUBLEJONG(short p_djong_idx, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_johapjaeum_idx >= SINGLE_JONG_SIZE && p_johapjaeum_idx < JONG_TABLE_SIZE);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.jong_idx = p_djong_idx;                                                                                                                                                                 //조합된 이중자음을 종성으로 사용
+    g_makecode.size = 1;                                                                                                                                                                                               //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);   //조합중인 글자의 유니코드
+
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= SINGLE_JONG_SIZE && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_DOUBLEJONG_2_CHO_JUNG : CHO_JUNG_DOUBLEJONG_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 조합종성이 나온상태에서 모음이 나올때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_DOUBLEJONG_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= SINGLE_JONG_SIZE && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    int tmp_jong_idx = DJONGIndexTable[g_makecode.jong_idx][0];                                        //이중자음의 제1자음 종성 인덱스를 가져온다.
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, tmp_jong_idx); //조합완료된 글자의 유니코드
+    p_madecode->size = 1;
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = DJONGIndexTable[g_makecode.jong_idx][1];                                                                              //조합중인 글자 종성 이중자음의 제2자음을 초성으로 사용
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    if (p_SIPKey == CHUN_MOEUM_AUTOMATA_INDEX) {       // "." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                                   //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                 //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_SIPKey];                                                                                              //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);                 //조합중인 글자의 유니코드
+    }
+
+
+    /* Automata History Stack */
+
+    /* 완료글자의 종성문자를 조합중인 문자의 초성으로 Automata History Stack에 Push 한다. */
+    int TMPstate = CHO_STATE;
+    MAKECODE TMPcode;
+    TMPcode.cho_idx = g_makecode.cho_idx;
+    TMPcode.size = 1;
+    TMPcode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];
+    pushEnvToAutomataHistoryStack(TMPstate, TMPcode);  //초성의 오토마타 환경을 저장
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_CHO_JUNG_DOUBLEJONG_2_CHO : CHO_JUNG_DOUBLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 조합종성이 나온상태에서 자음이 나올때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_CHO_JUNG_DOUBLEJONG_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(g_makecode.jong_idx >= SINGLE_JONG_SIZE && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->ucode[0] = getUnicodeWithCHO_JUNG_JONG(g_makecode.cho_idx, g_makecode.jung_idx, g_makecode.jong_idx);  //조합완료된 글자의 유니코드
+    p_madecode->size = 1;
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                     //조합중인 글자의 유니코드
+
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+
+    return;
+}
+
+
+/**
+*  초성과 중성으로 이루어진 글자의 Unicode를 얻어온다.
+*  !!!! 중성이 '.' 이 올수 있다. madecode 도 크기를 갖도록 수정해야 한다.
+*/
+short getUnicodeWithCHO_JUNG(short p_cho_idx, short p_jung_idx)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_cho_idx >= 0 && p_cho_idx < CHO_TABLE_SIZE);
+    ASSERT(p_jung_idx >= 0 && p_jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return (((p_cho_idx * 21) + p_jung_idx - 2) * 28) + 0xAC00;
+
+}
+
+/**
+*  초성 + 중성 + 종성으로 이루어진 글자의 Unicode를 얻어온다.
+*/
+short getUnicodeWithCHO_JUNG_JONG(short p_cho_idx, short p_jung_idx, short p_jong_idx)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_cho_idx >= 0 && p_cho_idx < CHO_TABLE_SIZE);
+    ASSERT(p_jung_idx >= 0 && p_jung_idx < JUNG_TABLE_SIZE);
+    ASSERT(p_jong_idx >= 0 && p_jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return (((p_cho_idx * 21) + p_jung_idx - 2) * 28) + (p_jong_idx + 1) + 0xAC00;
+
+}
+
+
+/**
+* 종성과 입력된 키가 결합한 이중 자음의 인덱스를 가져온다.
+* 종성과 입력된 SIPKey가 결합되어 이중자음을 생성할 때 사용 : Sparse Matrix 이나 프로그램으로 해결
+* - 입력
+*   p_first_jong_idx : 제1자음 - 종성 idx 사용
+*   p_second_SIPKEY_idx : 제2자음 - SIPKEY idx 사용
+* - return value : 이중자음의 인덱스 (종성 idx), COMBINATION_FAIL 결합불가
+*/
+
+int getJONGIndexofDJONG_withJONGandSIPKEY(int p_first_jong_idx, int p_second_SIPKEY_idx)
+{
+    switch (p_first_jong_idx) {
+    case 0 : //ㄱ
+        if (p_second_SIPKEY_idx == 9) { //ㅅ
+            return 2;     //ㄳ
+        }
+        break;
+    case 3 : //ㄴ
+        switch (p_second_SIPKEY_idx) {
+        case 12 : //ㅈ
+            return 4;     //ㄵ
+        case 18 : //ㅎ
+            return 5;    //ㄶ
+        default :
+            break;
+        }
+        break;
+    case 7 : //ㄹ
+        switch (p_second_SIPKEY_idx) {
+        case 0 : //ㄱ
+            return 8; //ㄺ
+        case 6 : //ㅁ
+            return 9; //ㄻ
+        case 7 : //ㅂ
+            return 10; //ㄼ
+        case 9 : //ㅅ
+            return 11; //ㄽ
+        case 16 : //ㅌ
+            return 12; //ㄾ
+        case 17 : //ㅍ
+            return 13; //ㄿ
+        case 18 : //ㅎ
+            return 14; //ㅀ
+        default :
+            break;
+        }
+        break;
+    case 16 : //ㅂ
+        if (p_second_SIPKEY_idx == 9) { //ㅅ
+            return 17;
+        }
+        break;
+    default :
+        break;
+    }
+
+    return COMBINATION_FAIL;
+}
+
+
+
+/**
+* 초성과 입력된 키가 결합한 이중 자음의 종성 인덱스를 가져온다.
+* - 초성에 이중자음이 나올 경우에 처리하기 위해 사용 : Sparse Matrix 이나 프로그램으로 해결
+* - 입력
+*   p_first_cho_idx : 제1자음 - 초성 idx 사용
+*   p_second_SIPKEY_idx : 제2자음 - SIPKEY idx 사용
+* - return value : 이중자음의 인덱스 (종성 idx), COMBINATION_FAIL 결합불가
+*/
+
+int getJONGIndexofDJONG_withCHOandSIPKEY(int p_first_cho_idx, int p_second_SIPKEY_idx)
+{
+    //switch (p_first_cho_idx) {
+    //case 0 : //ㄱ
+    //    if (p_second_SIPKEY_idx == 9) { //ㅅ
+    //        return 2;     //ㄳ
+    //    }
+    //    break;
+    //case 2 : //ㄴ
+    //    switch (p_second_SIPKEY_idx) {
+    //    case 12 : //ㅈ
+    //        return 4;     //ㄵ
+    //    case 18 : //ㅎ
+    //        return 5;          //ㄶ
+    //    default :
+    //        break;
+    //    }
+    //    break;
+    //case 5 : //ㄹ
+    //    switch (p_second_SIPKEY_idx) {
+    //    case 0 : //ㄱ
+    //        return 8; //ㄺ
+    //    case 6 : //ㅁ
+    //        return 9; //ㄻ
+    //    case 7 : //ㅂ
+    //        return 10; //ㄼ
+    //    case 9 : //ㅅ
+    //        return 11; //ㄽ
+    //    case 16 : //ㅌ
+    //        return 12; //ㄾ
+    //    case 17 : //ㅍ
+    //        return 13; //ㄿ
+    //    case 18 : //ㅎ
+    //        return 14; //ㅀ
+    //    default :
+    //        break;
+    //    }
+    //case 7 : //ㅂ
+    //    if (p_second_SIPKEY_idx == 9) { //ㅅ
+    //        return 17;  //ㅄ
+    //    }
+    //    break;
+    //default :
+    //    break;
+    //}
+
+    return COMBINATION_FAIL;
+}
+
+
+int getRotationKeyCanBeDOUBLEJONG(int p_first_jong_idx, int p_second_SIPKEY_idx)
+{
+    if (p_second_SIPKEY_idx >= SIPKEY_3X4_KEY_START && p_second_SIPKEY_idx <= SIPKEY_3X4_KEY_END) {
+        if (p_first_jong_idx >= 0 && p_first_jong_idx < JONG_TABLE_SIZE) {
+            return RotationKey_CanBe_DOUBLEJONG[p_first_jong_idx][p_second_SIPKEY_idx - SIPKEY_3X4_KEY_START];
+        }
+    }
+
+    return FALSE;
+}
+
+//--------------------------------- ERROR 처리 부분 --------------------------------------------------------
+
+/**
+*ACTION_ERROR_EMPTY_2_NOCHO_JUNG : EMPTY_STATE에서 NOCHO_JUNG_ERROR_STATE로 갈때 처리 - 초성없이 모음이 나올 떄
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_EMPTY_2_NOCHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용
+    g_makecode.cho_idx = EMPTY_CODE;                                   //초성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                               //조합중인 코드 사이즈 1
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 2
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx];                                                                   //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 1
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE;  //조합중인 글자의 유니코드
+    }
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_ERROR_CHO_2_CHO : CHO_STATE에서 CHO_STATE로 갈때 처리 - 초성 자음 뒤에 그것과 결합할 수 없는 초성 자음이 나옴
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_CHO_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];    //조합완료된 글자의 유니코드
+    p_madecode->size = 1;
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                                             //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+    return;
+}
+
+/**
+* ACTION_ERROR_CHO_2_NOCHO_NOJUNG_DOUBLEJONG : CHO_STATE 에서 NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE로 갈때 처리 - 초성과 중성 없이 조합종성이 만들어 지는 상태
+* - 입력
+*              p_djong_index : 조합된 이중자음의 index
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_CHO_2_NOCHO_NOJUNG_DOUBLEJONG(int p_djong_idx, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    g_makecode.jong_idx = p_djong_idx;                                                                                                                 //이중자음을 종성으로 사용
+    g_makecode.cho_idx = EMPTY_CODE;                                   //초성은 비어있음
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.size = 1;                                                                                                                                               //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[JONG2HCJAMOTable[p_djong_idx]];                                   //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_ERROR_CHO_JUNG_2_CHO : CHO_JUNG_STATE에서 CHO_STATE로 갈때 처리 - 초중에서 자음이 나왔으나 앞에 모음이 천('.') 또는 천천('..') 일때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_CHO_JUNG_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 2;                                                                                                                                              //조합 완료된 글자의 코드 사이즈 2
+    p_madecode->ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                            //조합 완료된 글자의 유니코드
+    p_madecode->ucode[1] = JUNGUnicodeTable[g_makecode.jung_idx];                                                              //조합 완료된 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                             //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                               //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                                     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+    return;
+}
+
+/**
+* ACTION_ERROR_CHO_JUNG_2_NOCHO_JUNG : CHO_JUNG_STATE에서 NOCHO_JUNG_STATE로 갈때 처리 - 초중상태에서 모음 조합중 결합하지 못하는 모음이 나올 떄
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_CHO_JUNG_2_NOCHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    // Pre Condition
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    // 조합완료 문자만들기
+    if(g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)      {       // "." 이거나 ".." 인 경우 처리
+        p_madecode->size = 2;                                                                                                                                          //조합 완료된 글자의 코드 사이즈 2
+        p_madecode->ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                //조합 완료된 글자의 유니코드
+        p_madecode->ucode[1] = JUNGUnicodeTable[g_makecode.jung_idx];                                                          //조합 완료된 글자의 유니코드
+    } else {
+        p_madecode->size = 1;                                                                                                                                          //조합 완료된 글자의 코드 사이즈 1
+        p_madecode->ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx);                //조합 완료된 글자의 유니코드
+    }
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    // 조합중인 문자만들기
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용
+    g_makecode.cho_idx = EMPTY_CODE;                                   //초성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                               //조합중인 코드 사이즈 1
+    if(g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)      {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 2
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx];                                                                   //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 1
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE;  //조합중인 글자의 유니코드
+    }
+
+#ifdef CJI_DEBUG
+    // Post Condition
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+    return;
+}
+
+
+/**
+* ACTION_ERROR_NOCHO_JUNG_2_CHO : NOCHO_JUNG_STATE에서 CHO_STATE로 갈때 처리 - 초성없이 모음 조합중 자음이 나올때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_NOCHO_JUNG_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        p_madecode->size = 1;                                                                                                                                                  //조합 완료된 글자의 코드 사이즈 2
+        p_madecode->ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx];                                                                  //조합 완료된 글자의 유니코드
+    } else {
+        p_madecode->size = 1;                                                                                                                                                  //조합 완료된 글자의 코드 사이즈 1
+        p_madecode->ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE; //조합 완료된 글자의 유니코드
+    }
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                             //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                               //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                                                     //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+    return;
+}
+
+/**
+* ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_NO : NOCHO_JUNG_STATE에서 NOCHO_JUNG_STATE로 갈때 처리 - 초성없이 모음 조합중 결합할 수 없는 모음이 나왔을 때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_NO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        p_madecode->size = 1;                                                                                                                                                  //조합 완료된 글자의 코드 사이즈 2
+        p_madecode->ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx];                                                                  //조합 완료된 글자의 유니코드
+    } else {
+        p_madecode->size = 1;                                                                                                                                                  //조합 완료된 글자의 코드 사이즈 1
+        p_madecode->ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE; //조합 완료된 글자의 유니코드
+    }
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                                        //입력문자를 중성으로 사용
+    g_makecode.cho_idx = EMPTY_CODE;                                   //초성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                               //조합중인 코드 사이즈 1
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 2
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx];                                                                   //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 1
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE;  //조합중인 글자의 유니코드
+    }
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+    return;
+}
+
+/**
+* ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_OK : NOCHO_JUNG_STATE에서 NOCHO_JUNG_STATE로 갈때 처리 - 초성없이 모음 조합중 결합 가능한 모음이 나올 때
+* - 입력
+*              p_jung_idx : 중성 인덱스
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_OK(short p_SIPKey, int p_jung_idx, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+    short prev_jung_idx;
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = IN_COMPOSITION;                                 //조합중이어서 조합완료된 코드가 없음을 표시
+
+    /* 조합중인 문자만들기 */
+    prev_jung_idx = g_makecode.jung_idx;                               //이전상태의 중성을 backup
+    g_makecode.jung_idx = p_jung_idx;                                                                                                                                  //입력문자를 중성으로 사용
+    g_makecode.cho_idx = EMPTY_CODE;                                   //초성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                               //조합중인 코드 사이즈 1
+    if (g_makecode.jung_idx == CHUN_MOEUM_AUTOMATA_INDEX || g_makecode.jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX)     {       // "." 이거나 ".." 인 경우 처리
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 2
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx];                                                                   //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                                   //조합중인 글자의 코드 사이즈 1
+        g_makecode.ucode[0] = JUNGUnicodeTable[g_makecode.jung_idx] + COMPENSATE_VALUE_FOR_JUNGUCODE;  //조합중인 글자의 유니코드
+    }
+
+    /* Automata History Stack */
+    /* ".." -> ".", "ㅑ"->"ㅏ', "ㅠ"->"ㅜ" 로 토글되는 경우에는 이전 상태를 Stack에서 제거 한다.
+    * "..", "ㅑ", "ㅠ" 를 " ", "ㅣ", "ㅡ" 상태로 만들어 주며 Next SIP 입력으로 현재 Env 저장시 "."이 Stack에 push되어 ".", "ㅏ", "ㅜ"로 복원
+    */
+    if (       ( prev_jung_idx == CHUN_CHUN_MOEUM_AUTOMATA_INDEX || prev_jung_idx == I_MOEUM_AUTOMATA_INDEX || prev_jung_idx == B_MOEUM_AUTOMATA_INDEX ) &&
+    (p_SIPKey == SIPKEY_IDX0) ) {
+        popFromAutomataHistoryStack();
+        popFromAutomataHistoryStack();
+    }
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO : NOCHO_NOJUNG_DOUBLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 초성과 중성없이 조합종성이 나온상태에서 자음이 나올때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_makecode.jong_idx >= 0 && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    p_madecode->size = 1;                                                                                                                                                      //조합 완료된 글자의 코드 사이즈 1
+    p_madecode->ucode[0] = HCJAMOUnicodeTable[JONG2HCJAMOTable[g_makecode.jong_idx]];                          //조합 완료된 글자의 유니코드
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = p_SIPKey;                                                                                                                                     //입력문자를 초성으로 사용
+    g_makecode.jung_idx = EMPTY_CODE;                                  //중성은 비어있음
+    g_makecode.jong_idx = EMPTY_CODE;                                  //종성은 비어있음
+    g_makecode.size = 1;                                                                                                                                                       //조합중인 코드 사이즈 1
+    g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                                                             //조합중인 글자의 유니코드
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+*ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO_JUNG : NOCHO_NOJUNG_DOUBLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 초성과 중성없이 조합종성이 나온상태에서 모음이 나올때
+* - 입력
+*              p_SIPKey : SIP 에서 들어온 입력 값 (SIPKEY)
+* - 출력
+*              g_makecode : 조합중인 글자의 크기와 유니코드 값
+*              p_madecode : 조합완료된 글자의 크기와 유니코드 값
+*/
+
+void ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode)
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_SIPKey >= 0 && p_SIPKey < 3);
+    ASSERT(g_makecode.jong_idx >= SINGLE_JONG_SIZE && g_makecode.jong_idx < JONG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+    /* 조합완료 문자만들기 */
+    int tmp_jong_idx = DJONGIndexTable[g_makecode.jong_idx][0];                                        //이중자음의 제1자음 종성 인덱스를 가져온다.
+    p_madecode->ucode[0] = HCJAMOUnicodeTable[JONG2HCJAMOTable[tmp_jong_idx]]; //조합완료된 글자의 유니코드
+    p_madecode->size = 1;
+    initAutomataHistoryStack();                                        //조합완료에 의한 History Stack clear
+
+    /* 조합중인 문자만들기 */
+    g_makecode.cho_idx = DJONGIndexTable[g_makecode.jong_idx][1];                                                              //조합중인 글자 종성 이중자음의 제2자음을 초성으로 사용
+    g_makecode.jung_idx = MOEUMAutomata[MOEUM_EMPTY][p_SIPKey];                                                                        //입력문자를 중성으로 사용
+    g_makecode.jong_idx = EMPTY_CODE;
+    if (p_SIPKey == CHUN_MOEUM_AUTOMATA_INDEX) {       // "." 인 경우 처리
+        g_makecode.size = 2;                                                                                                                                   //조합중인 코드 사이즈 2
+        g_makecode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];                                                 //조합중인 글자의 유니코드
+        g_makecode.ucode[1] = JUNGUnicodeTable[p_SIPKey];                                                                              //조합중인 글자의 유니코드
+    } else {
+        g_makecode.size = 1;                                                                                                                                   //조합중인 코드 사이즈 1
+        g_makecode.ucode[0] = getUnicodeWithCHO_JUNG(g_makecode.cho_idx, g_makecode.jung_idx); //조합중인 글자의 유니코드
+    }
+
+    /* Automata History Stack */
+
+    /* 완료글자의 종성문자를 조합중인 문자의 초성으로 Automata History Stack에 Push 한다. */
+    int TMPstate = CHO_STATE;
+    MAKECODE TMPcode;
+    TMPcode.cho_idx = g_makecode.cho_idx;
+    TMPcode.size = 1;
+    TMPcode.ucode[0] = HCJAMOUnicodeTable[CHO2HCJAMOTable[g_makecode.cho_idx]];
+    pushEnvToAutomataHistoryStack(TMPstate, TMPcode);  //초성의 오토마타 환경을 저장
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_makecode.cho_idx >= 0 && g_makecode.cho_idx < CHO_TABLE_SIZE);
+    ASSERT(g_makecode.jung_idx >= 0 && g_makecode.jung_idx < JUNG_TABLE_SIZE);
+#endif // CJI_DEBUG
+
+
+    return;
+}
+
+
+//----------------------------- Back Space를 처리하기 위한 Automata History Stack 관련 함수 ------------------------------
+
+/**
+* initializeAutomataHistoryStack : Automata History Stack 을 초기화 한다.
+* Stack의 Bottom 부분에 dummy 를 넣어 준다.
+*/
+void initAutomataHistoryStack()
+{
+    g_AH_Stack[0].state = EMPTY_STATE;
+    g_AH_Stack[0].makecode.size = 0;
+    g_AH_Stack[0].makecode.cho_idx = EMPTY_CODE;
+    g_AH_Stack[0].makecode.jung_idx = EMPTY_CODE;
+    g_AH_Stack[0].makecode.jong_idx = EMPTY_CODE;
+
+    g_AH_Stack_ptr = 0;
+
+    return;
+}
+
+/**
+* pushCurrentEnvToAutomataHistoryStack : 오토마타와 관련된 환경을 Automata History Stack 에 push 한다.
+* sunny 컴멘트는 optimize code로 나중에 확인하고 넣어 주자.
+*/
+void pushEnvToAutomataHistoryStack(int p_state, MAKECODE p_tmp_makecode)
+{
+
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(p_state > EMPTY_STATE);
+#endif // CJI_DEBUG
+
+    g_AH_Stack_ptr++;
+
+    g_AH_Stack[g_AH_Stack_ptr].state = p_state;
+    g_AH_Stack[g_AH_Stack_ptr].makecode.size = p_tmp_makecode.size;
+    g_AH_Stack[g_AH_Stack_ptr].makecode.ucode[0] = p_tmp_makecode.ucode[0];
+    g_AH_Stack[g_AH_Stack_ptr].makecode.ucode[1] = p_tmp_makecode.ucode[1];
+    g_AH_Stack[g_AH_Stack_ptr].makecode.cho_idx = p_tmp_makecode.cho_idx;
+    g_AH_Stack[g_AH_Stack_ptr].makecode.jung_idx = p_tmp_makecode.jung_idx;
+    g_AH_Stack[g_AH_Stack_ptr].makecode.jong_idx = p_tmp_makecode.jong_idx;
+
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_AH_Stack_ptr < MAX_AUTOMATA_HISTORY_LENGTH);
+#endif // CJI_DEBUG
+
+    return;
+}
+
+/**
+* popFromAutomataHistoryStack
+* - 오토마타의 이전 환경을 Automata History Stack에서 가져와서 오토마타의 상태와 조합중 코드(current_state, g_makecode)를 이전 환경로 복원한다.
+* - Stack pop을 통해 오토마타를 이전 환경으로 되돌린다.
+*/
+void popFromAutomataHistoryStack()
+{
+#ifdef CJI_DEBUG
+    /* Pre Condition */
+    ASSERT(g_AH_Stack_ptr > 0);
+#endif // CJI_DEBUG
+
+    //if (g_AH_Stack_ptr < 0) { //EMPTY STATE
+    if (g_AH_Stack_ptr <= 0) { //EMPTY STATE
+        current_state = EMPTY_STATE;
+        g_makecode.size = 0;
+    } else {
+        /* 오토마타의 상태와 조합중 코드를 이전환경으로 되돌림 */
+        current_state = g_AH_Stack[g_AH_Stack_ptr].state;
+        g_makecode.size = g_AH_Stack[g_AH_Stack_ptr].makecode.size;
+        g_makecode.ucode[0] = g_AH_Stack[g_AH_Stack_ptr].makecode.ucode[0];
+        g_makecode.ucode[1] = g_AH_Stack[g_AH_Stack_ptr].makecode.ucode[1];
+        g_makecode.cho_idx = g_AH_Stack[g_AH_Stack_ptr].makecode.cho_idx;
+        g_makecode.jung_idx = g_AH_Stack[g_AH_Stack_ptr].makecode.jung_idx;
+        g_makecode.jong_idx = g_AH_Stack[g_AH_Stack_ptr].makecode.jong_idx;
+
+        /* Stack pop */
+        g_AH_Stack_ptr--;
+    }
+
+#ifdef CJI_DEBUG
+    /* Post Condition */
+    ASSERT(g_AH_Stack[g_AH_Stack_ptr].state > 0);
+#endif // CJI_DEBUG
+
+    return;
+
+}
+
+/**
+* initAutomataEnv : Automata의 환경을 초기화 한다.
+* - Automata 관련 전역변수 초기화
+* - Automata History Stack 초기화
+*/
+void initAutomataEnv()
+{
+    current_state = EMPTY_STATE;               //current state 초기화
+    g_makecode.size = 0;
+    g_makecode.cho_idx = EMPTY_CODE;
+    g_makecode.jung_idx = EMPTY_CODE;
+    g_makecode.jong_idx = EMPTY_CODE;
+    g_makecode.ucode[0] = 0;
+    g_makecode.ucode[1] = 0;
+    initAutomataHistoryStack();
+}
diff --git a/src/sdk/cji.h b/src/sdk/cji.h
new file mode 100644 (file)
index 0000000..feb0b32
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _CJI_
+#define _CJI_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#ifndef FALSE
+#define FALSE   0
+#endif
+
+#ifndef TRUE
+#define TRUE    1
+#endif
+
+#define NUMBER_OF_STATE        9               /* STATE의 수 Iegal state 7 + illegal state 2*/
+
+    /**
+     * STATE 정의
+     * 1 : EMPTYial State - 한글 조합문자와 백스페이스 이외의 문자가 들어 온 상태
+     * 2 : 초성 - 초성을 조합하고 있는 상태
+     * 3 : 초성 + 중성 - 중성을 조합하고 있는 상태
+     * 4 : 초성 + 중성 + 단일종성 - 종성을 조합하고 있는 상태
+     * 5 : 초성 + 중성 + 조합종성 - 종성이 완료되었으나 제 2자음이 초성으로 쓰일지 종성으로 쓰일지 모르는 상태
+     * 6 : 초성 + 중성 이후 입력된 자음이 Rotation Key 로 인해 마지막 자음이 초성으로 쓰일지 종성으로 쓰일지 모르는 상태
+     * 7 : 초성 + 중성 + 단일종성 이후 입력된 자음이 Rotation Key 로 인해 마지막 자음이 초성으로 쓰일지 종성으로 쓰일지 모르는 상태
+     * 8 : 초성 없이 중성이 온 상태
+     * 9 : 초성 + 중성 없이 이중자음형태의 종성이 온 상태
+     */
+#define EMPTY_STATE                                                1
+#define        CHO_STATE                                                   2
+#define        CHO_JUNG_STATE                                      3
+#define        CHO_JUNG_SINGLEJONG_STATE                   4
+#define        CHO_JUNG_DOUBLEJONG_STATE                   5
+#define CHO_JUNG_CHO_STATE                                 6
+#define CHO_JUNG_SINGLEJONG_CHO_STATE           7
+#define NOCHO_JUNG_ERROR_STATE                     8
+#define        NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE     9
+
+
+    /**
+     * 사용용어정의
+     * 1. 단자음 : 하나로 이루어진 자음 11개 - ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ
+     * 2. 복자음 : 같은 자음 두개 로 이루어진다 5개 - ㄲㄸㅃㅆㅉ
+     * 3. 단일처리자음 : 단자음 + 복자음 으로 백스페이스로 지워지는 단위이다.
+     * 4. 이중자음 : 다른 자음 두개로 이루진다. 앞에 자음을 제 1자음, 뒤에 자음을 제 2자음이라 한다. 11개 - ㄳㄵㄶㄺㄻㄼㄽㄾㄿㅀㅄ
+     * 5. 단모음 : 키보드 상의 모음으로 하나의 처리단위로 백스페이스로 지워지는 단위이다. 14개 -ㅏ ㅑ ㅓ ㅕ ㅗ ㅛ ㅜ ㅠ ㅡ l ㅔ ㅐ ㅖ ㅒ
+     * 6. 이중모음 : 단모음으로 조합이 가능한 이중 모음, 앞의 모음을 제 1모음, 뒤의 모음을 제 2모음이라 한다. 7개 - ㅘ ㅙ ㅚ ㅝ ㅞ ㅟ ㅢ
+     */
+
+    /**
+     * SIPKEY LIST
+     * 사용하는 SIP(Software Input Panel) key의 인덱스 값 정의
+     * 자음과 모음은 isJaeum flag를 이용하여 구분한다.
+     */
+
+#define SIPKEY_IDX0    0       /* ㄱ */ /* . (천) */
+#define SIPKEY_IDX1    1       /* ㄲ */ /* ㅡ (지) */
+#define SIPKEY_IDX2    2       /* ㄴ */ /* ㅣ (인) */
+#define SIPKEY_IDX3    3       /* ㄷ */ /* ㅏ */
+#define SIPKEY_IDX4    4       /* ㄸ */ /* ㅑ */
+#define SIPKEY_IDX5    5       /* ㄹ */ /* ㅓ */
+#define SIPKEY_IDX6    6       /* ㅁ */ /* ㅕ */
+#define SIPKEY_IDX7    7       /* ㅂ */ /* ㅗ */
+#define SIPKEY_IDX8    8       /* ㅃ */ /* ㅛ */
+#define SIPKEY_IDX9    9       /* ㅅ */ /* ㅜ */
+#define SIPKEY_IDX10   10      /* ㅆ */ /* ㅠ */
+#define SIPKEY_IDX11   11      /* ㅇ */ /* ㅡ */
+#define SIPKEY_IDX12   12      /* ㅈ */ /* ㅣ */
+#define SIPKEY_IDX13   13      /* ㅉ */ /* ㅐ */
+#define SIPKEY_IDX14   14      /* ㅊ */ /* ㅔ */
+#define SIPKEY_IDX15   15      /* ㅋ */ /* ㅒ */
+#define SIPKEY_IDX16   16      /* ㅌ */ /* ㅖ */
+#define SIPKEY_IDX17   17      /* ㅍ */
+#define SIPKEY_IDX18   18      /* ㅎ */
+
+/* 3x4 keys */
+#define SIPKEY_IDX19   19      /* 3x4 4 Key */
+#define SIPKEY_IDX20   20      /* 3x4 5 Key */
+#define SIPKEY_IDX21   21      /* 3x4 6 Key */
+#define SIPKEY_IDX22   22      /* 3x4 7 Key */
+#define SIPKEY_IDX23   23      /* 3x4 8 Key */
+#define SIPKEY_IDX24   24      /* 3x4 9 Key */
+#define SIPKEY_IDX25   25      /* 3x4 0 Key */
+
+
+/* 3x4 key rotational table */
+#define SIPKEY_BACKSPACE       -2
+#define SIPKEY_ERROR   -1
+#define SIPKEY_3X4_KEY_ROTATION_CANIDATE_NUM 3
+#define SIPKEY_3X4_KEY_START SIPKEY_IDX19
+#define SIPKEY_3X4_KEY_END SIPKEY_IDX25
+#define SIPKEY_3X4_KEY_NUM (SIPKEY_3X4_KEY_END - SIPKEY_3X4_KEY_START + 1)
+
+       const static int SIPKEY3X4RotationTable[SIPKEY_3X4_KEY_NUM][SIPKEY_3X4_KEY_ROTATION_CANIDATE_NUM] = {
+               {SIPKEY_IDX0,   SIPKEY_IDX15,   SIPKEY_IDX1},   /* 3x4 4 Key */
+               {SIPKEY_IDX2,   SIPKEY_IDX5,    SIPKEY_ERROR},  /* 3x4 5 Key */
+               {SIPKEY_IDX3,   SIPKEY_IDX16,   SIPKEY_IDX4},   /* 3x4 6 Key */
+               {SIPKEY_IDX7,   SIPKEY_IDX17,   SIPKEY_IDX8},   /* 3x4 7 Key */
+               {SIPKEY_IDX9,   SIPKEY_IDX18,   SIPKEY_IDX10},  /* 3x4 8 Key */
+               {SIPKEY_IDX12,  SIPKEY_IDX14,   SIPKEY_IDX13},  /* 3x4 9 Key */
+               {SIPKEY_IDX11,  SIPKEY_IDX6,    SIPKEY_ERROR},  /* 3x4 0 Key */
+       };
+
+    /**
+     * SIPKEY Unicode 값 정의
+     */
+
+#define SIPKEY_TABLE_SIZE 19 /* 단자음 (14) + 복자음 (5) */
+
+    const static short SIPKEYUnicodeTable[SIPKEY_TABLE_SIZE] = {
+        0x1100,                /* 0 ㄱ */
+        0x1101,                /* 1 ㄲ */
+        0x1102,                /* 2 ㄴ */
+        0x1103,                /* 3 ㄷ */
+        0x1104,                /* 4 ㄸ */
+        0x1105,                /* 5 ㄹ */
+        0x1106,                /* 6 ㅁ */
+        0x1107,                /* 7 ㅂ */
+        0x1108,                /* 8 ㅃ */
+        0x1109,                /* 9 ㅅ */
+        0x110A,                /* 10 ㅆ */
+        0x110B,                /* 11 ㅇ */
+        0x110C,                /* 12 ㅈ */
+        0x110D,                /* 13 ㅉ */
+        0x110E,                /* 14 ㅊ */
+        0x110F,                /* 15 ㅋ */
+        0x1110,                /* 16 ㅌ */
+        0x1111,                /* 17 ㅍ */
+        0x1112,                /* 18 ㅎ */
+    };
+
+    /**
+     * 초성의 Unicode 값 정의
+     * SIPKEY 와 alias 한다.
+     */
+#define CHO_TABLE_SIZE SIPKEY_TABLE_SIZE
+
+
+    /**
+     * 중성의 Unicode 값 정의
+     */
+
+#define JUNG_TABLE_SIZE 23 /* 천(1) + 천천(1) + 단모음 (14) + 이중모음(7) = 23 */
+
+    const static short JUNGUnicodeTable[JUNG_TABLE_SIZE] = {
+        0x00B7,        /* 0 .(천) */ //0x119E  0x00B7  '.'
+        0x2025,        /* 1 ..(천천) */ //0x11A2 0x2025 '..'
+        0x1161,        /* 2 ㅏ */
+        0x1162,        /* 3 ㅐ */
+        0x1163,        /* 4 ㅑ */
+        0x1164,        /* 5 ㅒ */
+        0x1165,        /* 6 ㅓ */
+        0x1166,        /* 7 ㅔ */
+        0x1167,        /* 8 ㅕ */
+        0x1168,        /* 9 ㅖ */
+        0x1169,        /* 10 ㅗ */
+        0x116a,        /* 11 ㅘ */
+        0x116b,        /* 12 ㅙ */
+        0x116c,        /* 13 ㅚ */
+        0x116d,        /* 14 ㅛ */
+        0x116e,        /* 15 ㅜ */
+        0x116f,        /* 16 ㅝ */
+        0x1170,        /* 17 ㅞ */
+        0x1171,        /* 18 ㅟ */
+        0x1172,        /* 19 ㅠ */
+        0x1173,        /* 20 ㅡ */
+        0x1174,        /* 21 ㅢ */
+        0x1175,        /* 22 ㅣ */
+
+    };
+
+
+    /**
+     * 모음 오토마타
+     * - 현재 모음과 입력된 모음(천지인)이 결합하여 생성되는 모음의 index를 표시
+     * - COMBINATION_FAIL 은 결합 불가능을 표시
+     */
+
+#define MOEUMAUTOMATA_TABLE_SIZE JUNG_TABLE_SIZE+1     /* 중성 + Empty State */
+#define COMBINATION_FAIL -1 /* 모음 결합 실패 */
+
+#define CHUN_MOEUM_AUTOMATA_INDEX 0
+#define CHUN_CHUN_MOEUM_AUTOMATA_INDEX 1
+#define I_MOEUM_AUTOMATA_INDEX 4                       //'ㅑ'의 인덱스 - '.'에 의한 토글을 처리하기 위해
+#define B_MOEUM_AUTOMATA_INDEX 19                      //'ㅠ'의 인덱스 - '.'에 의한 토글을 처리하기 위해
+
+#define U_MOEUM_AUTOMATA_INDEX 6                       //'ㅓ'의 인덱스 - 'ㅕ' 처리하기 위해
+#define O_MOEUM_AUTOMATA_INDEX 10                      //'ㅗ'의 인덱스 - 'ㅛ' 처리하기 위해
+#define YEO_MOEUM_AUTOMATA_INDEX 8                     //'ㅕ'의 인덱스
+#define YO_MOEUM_AUTOMATA_INDEX 14                     //'ㅛ'의 인덱스
+
+#define MOEUM_EMPTY 23
+
+    const static int MOEUMAutomata[MOEUMAUTOMATA_TABLE_SIZE][17] = {
+/*                                     .(천)                          지(ㅡ)                                인(ㅣ)                                ㅏ                                     ㅑ                                     ㅓ                                     ㅕ                                     ㅗ                                     ㅛ                                     ㅜ                                     ㅠ                                     ㅡ                                     ㅣ                                     ㅐ                                     ㅔ                                     ㅒ                                     ㅖ */
+/* 0 .(천) */         {1,                                     10,                                     6,                                      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 1 ..(천천) */     {0,                                     14,                                     8,                                      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 2 ㅏ */                    {4,                                     COMBINATION_FAIL,       3,                                      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 3 ㅐ */                    {5,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 4 ㅑ */                    {2,                                     COMBINATION_FAIL,       5,                                      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 5 ㅒ */                    {3,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 6 ㅓ */                    {8,                                     COMBINATION_FAIL,       7,                                      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 7 ㅔ */                    {9                              ,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 8 ㅕ */                    {6,                                     COMBINATION_FAIL,       9,                                      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 9 ㅖ */                    {7,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 10 ㅗ */                   {COMBINATION_FAIL,      COMBINATION_FAIL,       13,                                     11,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       13,                                     12,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 11 ㅘ */                   {COMBINATION_FAIL,      COMBINATION_FAIL,       12,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 12 ㅙ */                   {COMBINATION_FAIL,      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 13 ㅚ */                   {11,                            COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 14 ㅛ */                   {10,                            COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 15 ㅜ */                   {19,                            COMBINATION_FAIL,       18,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       16,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       18,                                     COMBINATION_FAIL,       17,                                     COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 16 ㅝ */                   {COMBINATION_FAIL,      COMBINATION_FAIL,       17,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 17 ㅞ */                   {COMBINATION_FAIL,      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 18 ㅟ */                   {16,                            COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 19 ㅠ */                   {15,                            COMBINATION_FAIL,       16,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 20 ㅡ */                   {15,                            COMBINATION_FAIL,       21,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       21,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 21 ㅢ */                   {COMBINATION_FAIL,      COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 22 ㅣ */                   {2,                                     COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL,       COMBINATION_FAIL},
+/* 23 EMPTY */         {0,                                     20,                                     22,                                     2,                                      4,                                      6,                                      8,                                      10,                                     14,                                     15,                                     19,                                     20,                                     22,                                     3,                                      7,                                      5,                                      9,},
+    };
+
+
+    /**
+     * 종성의 Unicode 값 정의
+     */
+
+#define JONG_TABLE_SIZE 27 /* 단자음 (14) + 복자음 (ㄲ, ㅆ) + 이중자음(11) = 27*/
+
+    const static short JONGUnicodeTable[JONG_TABLE_SIZE] = {
+        0x11A8,                /* 0 ㄱ */
+        0x11A9,                /* 1 ㄲ */
+        0x11AA,                /* 2 ㄳ */
+        0x11AB,                /* 3 ㄴ */
+        0x11AC,                /* 4 ㄵ */
+        0x11AD,                /* 5 ㄶ */
+        0x11AE,                /* 6 ㄷ */
+        0x11AF,                /* 7 ㄹ */
+        0x11B0,                /* 8 ㄺ */
+        0x11B1,                /* 9 ㄻ */
+        0x11B2,                /* 10 ㄼ */
+        0x11B3,                /* 11 ㄽ */
+        0x11B4,                /* 12 ㄾ */
+        0x11B5,                /* 13 ㄿ */
+        0x11B6,                /* 14 ㅀ */
+        0x11B7,                /* 15 ㅁ */
+        0x11B8,                /* 16 ㅂ */
+        0x11B9,                /* 17 ㅄ */
+        0x11BA,                /* 18 ㅅ */
+        0x11BB,                /* 19 ㅆ */
+        0x11BC,                /* 20 ㅇ */
+        0x11BD,                /* 21 ㅈ */
+        0x11BE,                /* 22 ㅊ */
+        0x11BF,                /* 23 ㅋ */
+        0x11C0,                /* 24 ㅌ */
+        0x11C1,                /* 25 ㅍ */
+        0x11C2,                /* 26 ㅎ */
+    };
+
+    /**
+     * 이중자음이 어떤 단자음의 결합으로 이루어졌는지를 나타내는 테이블 : 이중자음이 분리되어 종성과 초성으로 사용될 때 쓰임
+     * 이중자음의 종성인덱스를 이용하여 테이블을 서치하여 제1자음의 종성인덱스와 제 2 자음의 초성인덱스를 가져온다.
+     */
+
+#define INVALID -1  /* 단일처리자음인 경우 : 제 1자음과 제 2자음으로 나누어 사용할 수 없음*/
+
+    const static int DJONGIndexTable[JONG_TABLE_SIZE][2] = {
+        /*     제 1자음     제 2자음             */
+               {INVALID,       INVALID},                               /* 0 ㄱ */
+        {INVALID,      INVALID},                               /* 1 ㄲ */
+        {0,                            9},                                     /* 2 ㄳ */
+        {INVALID,      INVALID},                               /* 3 ㄴ */
+        {3,                            12},                            /* 4 ㄵ */
+        {3,                            18},                            /* 5 ㄶ */
+        {INVALID,      INVALID},                               /* 6 ㄷ */
+        {INVALID,      INVALID},                               /* 7 ㄹ */
+        {7,                            0},                                     /* 8 ㄺ */
+        {7,                            6},                                     /* 9 ㄻ */
+        {7,                            7},                                     /* 10 ㄼ */
+        {7,                            9},                                     /* 11 ㄽ */
+        {7,                            16},                            /* 12 ㄾ */
+        {7,                            17},                            /* 13 ㄿ */
+        {7,                            18},                            /* 14 ㅀ */
+        {INVALID,      INVALID},                               /* 15 ㅁ */
+        {INVALID,      INVALID},                               /* 16 ㅂ */
+        {16,                   9},                                     /* 17 ㅄ */
+        {INVALID,      INVALID},                               /* 18 ㅅ */
+        {INVALID,      INVALID},                               /* 19 ㅆ */
+        {INVALID,      INVALID},                               /* 20 ㅇ */
+        {INVALID,      INVALID},                               /* 21 ㅈ */
+        {INVALID,      INVALID},                               /* 22 ㅊ */
+        {INVALID,      INVALID},                               /* 23 ㅋ */
+        {INVALID,      INVALID},                               /* 24 ㅌ */
+        {INVALID,      INVALID},                               /* 25 ㅍ */
+        {INVALID,      INVALID},                               /* 26 ㅎ */
+
+    };
+
+
+    /**
+     * HCJAMO(Hangul Compatibility Jamo) Unicode Table
+     * - 초성이나 중성, 종성등이 조합되지 않고 단독으로 쓰일 때는 Unicode Hangul Compatibility Jamo 를 사용해야 한다.
+     * - 중성의 경우는 중성 Unicode에 보정값을 더하여 Hangul Compatibility Jamo unicode를 변환이 가능하다.
+     * - 따라서 자음부분만을 정의하여 사용하였다.
+     */
+
+#define HCJAMO_TABLE_SIZE 30 /* 단자음 (14) + 복자음 (5) + 이중자음 (11) = 30 */
+
+    const static short HCJAMOUnicodeTable[HCJAMO_TABLE_SIZE] = {
+        0x3131,                /* 0 ㄱ */
+        0x3132,                /* 1 ㄲ */
+        0x3133,                /* 2 ㄳ */
+        0x3134,                /* 3 ㄴ */
+        0x3135,                /* 4 ㄵ */
+        0x3136,                /* 5 ㄶ */
+        0x3137,                /* 6 ㄷ */
+        0x3138,                /* 7 ㄸ */
+        0x3139,                /* 8 ㄹ */
+        0x313A,                /* 9 ㄺ */
+        0x313B,                /* 10 ㄻ */
+        0x313C,                /* 11 ㄼ */
+        0x313D,                /* 12 ㄽ */
+        0x313E,                /* 13 ㄾ */
+        0x313F,                /* 14 ㄿ */
+        0x3140,                /* 15 ㅀ */
+        0x3141,                /* 16 ㅁ */
+        0x3142,                /* 17 ㅂ */
+        0x3143,                /* 18 ㅃ */
+        0x3144,                /* 19 ㅄ */
+        0x3145,                /* 20 ㅅ */
+        0x3146,                /* 21 ㅆ */
+        0x3147,                /* 22 ㅇ */
+        0x3148,                /* 23 ㅈ */
+        0x3149,                /* 24 ㅉ */
+        0x314A,                /* 25 ㅊ */
+        0x314B,                /* 26 ㅋ */
+        0x314C,                /* 27 ㅌ */
+        0x314D,                /* 28 ㅍ */
+        0x314E,                /* 29 ㅎ */
+
+    };
+
+    /**
+     * 중성 Unicode를 Hangul Compatibility Jamo unicode로 변환하기 위한 보정값
+     * '.'과 '..'을 제외하고 JUNGUnicodeTable[idx] + 0x1FEE 로 컨버젼 가능
+     */
+#define COMPENSATE_VALUE_FOR_JUNGUCODE 0x1FEE
+
+
+    /**
+     * 종성불가 자음 정의 테이블
+     * - 현재 입력으로 들어온 SIPKEY가 종성으로 사용될 수 있는 지를 표시
+     * - 종성불가이면 조합중인 글자를 완료 시키고 항상 초성으로 사용될 수 있도록 한다.
+     */
+    const static int CANTJONGTable[] = {
+        TRUE,          /* 0 ㄱ */
+        TRUE,          /* 1 ㄲ */
+        TRUE,          /* 2 ㄴ */
+        TRUE,          /* 3 ㄷ */
+        FALSE,         /* 4 ㄸ */
+        TRUE,          /* 5 ㄹ */
+        TRUE,          /* 6 ㅁ */
+        TRUE,          /* 7 ㅂ */
+        FALSE,         /* 8 ㅃ */
+        TRUE,          /* 9 ㅅ */
+        TRUE,          /* 10 ㅆ */
+        TRUE,          /* 11 ㅇ */
+        TRUE,          /* 12 ㅈ */
+        FALSE,         /* 13 ㅉ */
+        TRUE,          /* 14 ㅊ */
+        TRUE,          /* 15 ㅋ */
+        TRUE,          /* 16 ㅌ */
+        TRUE,          /* 17 ㅍ */
+        TRUE,          /* 18 ㅎ */
+    };
+
+    /**
+     * 종성을 초성의 index로 바꾸는 테이블
+     * - 조합중인 글자의 종성을 새로운 글자의 초성으로 사용할 때 쓰임
+     * - '굴'에서 'ㅣ'가 들어 와서 '구''리'가 되는 경우
+     */
+    const static int JONG2CHOTable[JONG_TABLE_SIZE] = {
+        0,                             /* 0 ㄱ */
+        1,                             /* 1 ㄲ */
+        INVALID,               /* 2 ㄳ */
+        2,                             /* 3 ㄴ */
+        INVALID,               /* 4 ㄵ */
+        INVALID,               /* 5 ㄶ */
+        3,                             /* 6 ㄷ */
+        5,                             /* 7 ㄹ */
+        INVALID,               /* 8 ㄺ */
+        INVALID,               /* 9 ㄻ */
+        INVALID,               /* 10 ㄼ */
+        INVALID,               /* 11 ㄽ */
+        INVALID,               /* 12 ㄾ */
+        INVALID,               /* 13 ㄿ */
+        INVALID,               /* 14 ㅀ */
+        6,                             /* 15 ㅁ */
+        7,                             /* 16 ㅂ */
+        INVALID,               /* 17 ㅄ */
+        9,                             /* 18 ㅅ */
+        10,                            /* 19 ㅆ */
+        11,                            /* 20 ㅇ */
+        12,                            /* 21 ㅈ */
+        14,                            /* 22 ㅊ */
+        15,                            /* 23 ㅋ */
+        16,                            /* 24 ㅌ */
+        17,                            /* 25 ㅍ */
+        18,                            /* 26 ㅎ */
+    };
+
+
+    /**
+     * SIPKEY를 종성의 index로 바꾸는 테이블
+     * - 입력된 SIPKEY가 조합중인 글자의 종성으로 사용될 때 쓰임
+     * - '구'에서 'ㄹ'이 입력되어 '굴'이 생성된 경우 'ㄹ'의 SIPKEY 인덱스를 '굴'에서 사용될 수 있도록 종성 인덱스로 바꾸어 준다
+     */
+    const static short SIPKEY2JONGTable[SIPKEY_TABLE_SIZE] = {
+        0,             /* 0 ㄱ */
+        1,             /* 1 ㄲ */
+        3,             /* 2 ㄴ */
+        6,             /* 3 ㄷ */
+        INVALID,/* 4 ㄸ */
+        7,             /* 5 ㄹ */
+        15,            /* 6 ㅁ */
+        16,            /* 7 ㅂ */
+        INVALID,/* 8 ㅃ */
+        18,            /* 9 ㅅ */
+        19,            /* 10 ㅆ */
+        20,            /* 11 ㅇ */
+        21,            /* 12 ㅈ */
+        INVALID,/* 13 ㅉ */
+        22,            /* 14 ㅊ */
+        23,            /* 15 ㅋ */
+        24,            /* 16 ㅌ */
+        25,            /* 17 ㅍ */
+        26,            /* 18 ㅎ */
+    };
+
+    /**
+     * 초성을 HCJAMO Unicode의 index로 바꾸는 테이블
+     * - CHO_STATE에서 조합중인 글자를 표시하기 위해 사용
+     */
+    const static short CHO2HCJAMOTable[CHO_TABLE_SIZE] = {
+        0,             /* 0 ㄱ */
+        1,             /* 1 ㄲ */
+        3,             /* 2 ㄴ */
+        6,             /* 3 ㄷ */
+        7,             /* 4 ㄸ */
+        8,             /* 5 ㄹ */
+        16,            /* 6 ㅁ */
+        17,            /* 7 ㅂ */
+        18,            /* 8 ㅃ */
+        20,            /* 9 ㅅ */
+        21,            /* 10 ㅆ */
+        22,            /* 11 ㅇ */
+        23,            /* 12 ㅈ */
+        24,            /* 13 ㅉ */
+        25,            /* 14 ㅊ */
+        26,            /* 15 ㅋ */
+        27,            /* 16 ㅌ */
+        28,            /* 17 ㅍ */
+        29,            /* 18 ㅎ */
+    };
+
+
+    /**
+     * 종성을 HCJAMO Unicode의 index로 바꾸는 테이블
+     * - 초성과 초성이 결합하여 종성이중자음이 될때 이를 표시하기 위해 사용
+     * - 'ㄱ'에서 'ㅅ'이 들어 와서 'ㄳ'이 되는 경우
+     */
+    const static int JONG2HCJAMOTable[JONG_TABLE_SIZE] = {
+        0,                             /* 0 ㄱ */
+        1,                             /* 1 ㄲ */
+        2,                             /* 2 ㄳ */
+        3,                             /* 3 ㄴ */
+        4,                             /* 4 ㄵ */
+        5,                             /* 5 ㄶ */
+        6,                             /* 6 ㄷ */
+        8,                             /* 7 ㄹ */
+        9,                             /* 8 ㄺ */
+        10,                            /* 9 ㄻ */
+        11,                            /* 10 ㄼ */
+        12,                            /* 11 ㄽ */
+        13,                            /* 12 ㄾ */
+        14,                            /* 13 ㄿ */
+        15,                            /* 14 ㅀ */
+        16,                            /* 15 ㅁ */
+        17,                            /* 16 ㅂ */
+        19,                            /* 17 ㅄ */
+        20,                            /* 18 ㅅ */
+        21,                            /* 19 ㅆ */
+        22,                            /* 20 ㅇ */
+        23,                            /* 21 ㅈ */
+        25,                            /* 22 ㅊ */
+        26,                            /* 23 ㅋ */
+        27,                            /* 24 ㅌ */
+        28,                            /* 25 ㅍ */
+        29,                            /* 26 ㅎ */
+    };
+
+
+    typedef struct makecodeinfo {
+        int size; // 조합중인 코드의 크기 (자음 + 천(.) 이나 자음 + 천천(..) 은 2, 나머지는 1)
+        short ucode[2]; // 조합중인 글자의 유니코드 값
+        short cho_idx;
+        short jung_idx;
+        short jong_idx;
+        short next_cho_idx;
+    } MAKECODE;
+
+
+    typedef struct madecodeinfo {
+        int size; // 조합 완료된 코드의 크기 (자음 + 천(.) 이나 자음 + 천천(..) 은 2, 나머지는 1, 조합완료된 코드가 없는 경우 0)
+        short ucode[2]; // 조합중인 글자의 유니코드 값
+    } MADECODE;
+
+
+#define IN_COMPOSITION 0       /* 조합중이어서 조합완료된 코드가 없음을 표시 */
+
+
+//---- Back space 처리를 위한 정의 부분 start -----------
+    typedef struct automatahistoryinfo {
+        int state;                             //오토마타의 상태
+        MAKECODE makecode;             //조합중인 글자
+    } AUTOMATA_HISTORY_INFO;
+
+#define MAX_AUTOMATA_HISTORY_LENGTH 10 // 자음(2) + 모음(5) + 자음(2) + 더미(1) = 10
+
+#define EMPTY_CODE -1
+
+    /**
+     * Back Space 가 눌렸을 때 모음부분을 처리하기 위한 Automata History Stack POP 정보
+     * - 자음은 입력단위로 지워지나 모음은 입력단위가 아닌 단모음 단위로 지워진다.
+     */
+    const static int BS_MOEUMInfo[JUNG_TABLE_SIZE] = {
+        1,     /* 0 .(천) */
+        2,     /* 1 ..(천천) */
+        2,     /* 2 ㅏ */
+        3,     /* 3 ㅐ */
+        3,     /* 4 ㅑ */
+        4,     /* 5 ㅒ */
+        2,     /* 6 ㅓ */
+        3,     /* 7 ㅔ */
+        3,     /* 8 ㅕ */
+        4,     /* 9 ㅖ */
+        2,     /* 10 ㅗ */
+        2,     /* 11 ㅘ */
+        3,     /* 12 ㅙ */
+        1,     /* 13 ㅚ */
+        3,     /* 14 ㅛ */
+        2,     /* 15 ㅜ */
+        2,     /* 16 ㅝ */
+        3,     /* 17 ㅞ */
+        1,     /* 18 ㅟ */
+        3,     /* 19 ㅠ */
+        1,     /* 20 ㅡ */
+        2,     /* 21 ㅢ */
+        1,     /* 22 ㅣ */
+    };
+
+       /**
+       * Back Space 가 눌렸을 때 모음부분을 처리하기 위한 모음 변환 Table
+       * - 자음은 입력단위로 지워지나 모음은 입력단위가 아닌 단모음 단위로 지워진다.
+       */
+       const static int BS_MOEUMInfo_Automata[JUNG_TABLE_SIZE] = {
+               EMPTY_CODE,     /* 0 .(천) */
+               EMPTY_CODE,     /* 1 ..(천천) */
+               EMPTY_CODE,     /* 2 ㅏ */
+               EMPTY_CODE,     /* 3 ㅐ */
+               EMPTY_CODE,     /* 4 ㅑ */
+               EMPTY_CODE,     /* 5 ㅒ */
+               EMPTY_CODE,     /* 6 ㅓ */
+               EMPTY_CODE,     /* 7 ㅔ */
+               EMPTY_CODE,     /* 8 ㅕ */
+               EMPTY_CODE,     /* 9 ㅖ */
+               EMPTY_CODE,     /* 10 ㅗ */
+               10,                     /* 11 ㅘ */ /* -> ㅗ */
+               10,                     /* 12 ㅙ */ /* -> ㅗ */
+               10,                     /* 13 ㅚ */ /* -> ㅗ */
+               EMPTY_CODE,     /* 14 ㅛ */
+               EMPTY_CODE,     /* 15 ㅜ */
+               15,                     /* 16 ㅝ */ /* -> ㅜ */
+               15,                             /* 17 ㅞ */ /* -> ㅜ */
+               15,                     /* 18 ㅟ */ /* -> ㅜ */
+               EMPTY_CODE,     /* 19 ㅠ */
+               EMPTY_CODE,     /* 20 ㅡ */
+               20,                             /* 21 ㅢ */ /* -> ㅡ */
+               EMPTY_CODE,     /* 22 ㅣ */
+       };
+
+
+       /**
+       * 3X4 Rotation을 통해 종성이중자음이 될 수 있는 Key를 나타내는 테이블
+       * - 입력된 자음 Key가 이전 조합글자와 Composition state를 유지해야 하는지를 판단
+       * - '할'에서 'ㄷ'이 입력되어 '할ㄷ'이 생성된 경우 'ㄷ'이 'ㅌ'로 Rotation되어 '핥' 이 될 수 있으므로
+       * - Composition State를 유지해야 하는데, 이러한 판단을 하기 위한 Table
+       */
+       const static bool RotationKey_CanBe_DOUBLEJONG[JONG_TABLE_SIZE][SIPKEY_3X4_KEY_NUM] = {
+               // 3X4_4Key,    3X4_5Key,       3X4_6Key,       3X4_7Key,       3X4_8Key,       3X4_9Key,       3X4_0Key,
+               {FALSE,                 FALSE,          FALSE,          FALSE,          TRUE,           FALSE,          FALSE},         /* 0 ㄱ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 1 ㄲ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 2 ㄳ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          TRUE,           TRUE,           FALSE},         /* 3 ㄴ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 4 ㄵ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 5 ㄶ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 6 ㄷ */
+               {TRUE,                  FALSE,          TRUE,           TRUE,           TRUE,           FALSE,          TRUE},          /* 7 ㄹ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 8 ㄺ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 9 ㄻ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 10 ㄼ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 11 ㄽ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 12 ㄾ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 13 ㄿ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 14 ㅀ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 15 ㅁ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          TRUE,           FALSE,          FALSE},         /* 16 ㅂ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 17 ㅄ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 18 ㅅ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 19 ㅆ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 20 ㅇ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 21 ㅈ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 22 ㅊ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 23 ㅋ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 24 ㅌ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 25 ㅍ */
+               {FALSE,                 FALSE,          FALSE,          FALSE,          FALSE,          FALSE,          FALSE},         /* 26 ㅎ */
+       };
+
+
+//------ Back space 처리를 위한 정의 부분 end -----------
+
+
+    /* 한글 조합을 처리하는 오토 마타의 메인 부분이다. */
+    int CJI_Automata(int p_isJAEUM, short p_SIPKey, MADECODE *p_madecode);
+
+    /* Get current make code, which means the character currently being composed */
+    MAKECODE CJI_GetMakeCode();
+
+    /* This saves/loads current state of automata */
+    void Backup_Automata();
+    void Restore_Automata();
+
+    /* ---------------- state 간의 전이시 수행하는 action 부분이다. ----------------------- */
+
+    /* ACTION_EMPTY_2_CHO : EMPTY_STATE에서 CHO_STATE로 갈때 처리 */
+    void ACTION_EMPTY_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_CHO_2_CHO_JUNG : CHO_STATE에서 CHO_JUNG_STATE로 갈때 처리 */
+    void ACTION_CHO_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_2_CHO_JUNG : CHO_JUNG_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 모음이 계속 조합될 때 */
+    void ACTION_CHO_JUNG_2_CHO_JUNG(short p_SIPKey, short p_jung_idx, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_2_CHO : CHO_JUNG_STATE에서 CHO_STATE로 갈때 처리 - 종성불가자음 이 올 때 */
+    void ACTION_CHO_JUNG_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+       bool ACTION_ERROR_KEY(short p_SIPKey, MADECODE *p_madecode);
+       bool ACTION_BACKSPACE_KEY(short p_SIPKey, MADECODE *p_madecode);
+
+       /* ACTION_CHO_JUNG_2_CHO_JUNG_CHO : CHO_JUNG_STATE에서 CHO_JUNG_CHO_STATE로 갈때 처리 - 3X4 Rotation 종성불가자음 이 올 때 */
+       void ACTION_CHO_JUNG_2_CHO_JUNG_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+       /* ACTION_CHO_JUNG_CHO_2_CHO : CHO_JUNG_CHO_STATE에서 CHO_STATE로 갈때 처리 - 다른 자음Key 입력시 */
+       void ACTION_CHO_JUNG_CHO_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+       /* ACTION_CHO_JUNG_CHO_2_CHO_JUNG : CHO_JUNG_CHO_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 모음 입력시 */
+       void ACTION_CHO_JUNG_CHO_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+       /* ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_SINGLEJONG_CHO : CHO_JUNG_SINGLEJONG_STATE에서 CHO_JUNG_SINGLEJONG_CHO_STATE로 갈때 처리 - 3X4 Rotation 종성조합불가자음 이 올 때 */
+       void ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_SINGLEJONG_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+       /* ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO : CHO_JUNG_SINGLEJONG_CHO_STATE에서 CHO_STATE로 갈때 처리 - 다른 자음Key 입력시 */
+       void ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+       /* ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO_JUNG : CHO_JUNG_SINGLEJONG_CHO_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 모음 입력시 */
+       void ACTION_CHO_JUNG_SINGLEJONG_CHO_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+       // }
+
+    /* ACTION_CHO_JUNG_2_CHO_JUNG_SINGLEJONG : CHO_JUNG_STATE에서 CHO_JUNG_SINGLEJONG_STATE로 갈때 처리 - 종성으로 단일자음 사용 */
+    void ACTION_CHO_JUNG_2_CHO_JUNG_SINGLEJONG(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG : CHO_JUNG_SINGLEJONG_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 종성이 나온 상태에서 모음이 나올 때 */
+    void ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_SINGLEJONG_2_CHO : CHO_JUNG_SINGLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 종성조합불가자음이 나올때 */
+    void ACTION_CHO_JUNG_SINGLEJONG_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_DOUBLEJONG : CHO_JUNG_SINGLEJONG_STATE에서 CHO_JUNG_DOUBLEJONG_STATE로 갈때 처리 - 종성조합가능자음이 나올때 */
+    void ACTION_CHO_JUNG_SINGLEJONG_2_CHO_JUNG_DOUBLEJONG(short p_johapjaeum_idx, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_DOUBLEJONG_2_CHO_JUNG : CHO_JUNG_DOUBLEJONG_STATE에서 CHO_JUNG_STATE로 갈때 처리 - 조합종성이 나온상태에서 모음이 나올때 */
+    void ACTION_CHO_JUNG_DOUBLEJONG_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_CHO_JUNG_DOUBLEJONG_2_CHO : CHO_JUNG_DOUBLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 조합종성이 나온상태에서 자음이 나올때 */
+    void ACTION_CHO_JUNG_DOUBLEJONG_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* --------------- state 전이시 발생하는 ERROR를 처리하기 위한 action 부분이다. ------------------ */
+
+    /* ACTION_ERROR_EMPTY_2_NOCHO_JUNG : EMPTY_STATE에서 NOCHO_JUNG_ERROR_STATE로 갈때 처리 - 초성없이 모음이 나올 떄 */
+    void ACTION_ERROR_EMPTY_2_NOCHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_CHO_2_CHO : CHO_STATE에서 CHO_STATE로 갈때 처리 - 초성 자음 뒤에 그것과 결합할 수 없는 초성 자음이 나옴 */
+    void ACTION_ERROR_CHO_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_CHO_2_NOCHO_NOJUNG_DOUBLEJONG : CHO_STATE 에서 NOCHO_NOJUNG_DOUBLEJONG_ERROR_STATE로 갈때 처리 - 초성과 중성 없이 조합종성이 만들어 지는 상태 */
+    void ACTION_ERROR_CHO_2_NOCHO_NOJUNG_DOUBLEJONG(int johapjaeum_idx, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_CHO_JUNG_2_CHO : CHO_JUNG_STATE에서 CHO_STATE로 갈때 처리 - 초중에서 자음이 나왔으나 앞에 모음이 천('.') 또는 천천('..') 일때 */
+    void ACTION_ERROR_CHO_JUNG_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_CHO_JUNG_2_NOCHO_JUNG : CHO_JUNG_STATE에서 NOCHO_JUNG_STATE로 갈때 처리 - 초중상태에서 모음 조합중 결합하지 못하는 모음이 나올 떄 */
+    void ACTION_ERROR_CHO_JUNG_2_NOCHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_NOCHO_JUNG_2_CHO : NOCHO_JUNG_STATE에서 CHO_STATE로 갈때 처리 - 초성없이 모음 조합중 자음이 나올때 */
+    void ACTION_ERROR_NOCHO_JUNG_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_NO : NOCHO_JUNG_STATE에서 NOCHO_JUNG_STATE로 갈때 처리 - 초성없이 모음 조합중 결합할 수 없는 모음이 나왔을 때 */
+    void ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_NO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_OK : NOCHO_JUNG_STATE에서 NOCHO_JUNG_STATE로 갈때 처리 - 초성없이 모음 조합중 결합 가능한 모음이 나올 때 */
+    void ACTION_ERROR_NOCHO_JUNG_2_NOCHO_JUNG_COMBINATION_OK(short p_SIPKey, int p_jung_idx, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO : NOCHO_NOJUNG_DOUBLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 초성과 중성없이 조합종성이 나온상태에서 자음이 나올때 */
+    void ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO(short p_SIPKey, MADECODE *p_madecode);
+
+    /* ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO_JUNG : NOCHO_NOJUNG_DOUBLEJONG_STATE에서 CHO_STATE로 갈때 처리 - 초성과 중성없이 조합종성이 나온상태에서 모음이 나올때 */
+    void ACTION_ERROR_NOCHO_NOJUNG_DOUBLEJONG_2_CHO_JUNG(short p_SIPKey, MADECODE *p_madecode);
+
+//-------------------- 내부 인덱스로 Unicode 값을 얻어 온다. --------------
+    /* 초성과 중성으로 이루어진 글자의 Unicode를 얻어온다. */
+    short getUnicodeWithCHO_JUNG(short p_cho_idx, short p_jung_idx);
+
+    /* 초성 + 중성 + 종성으로 이루어진 글자의 Unicode를 얻어온다. */
+    short getUnicodeWithCHO_JUNG_JONG(short p_cho_idx, short p_jung_idx, short p_jong_idx);
+
+    /* 종성과 입력된 키가 결합한 이중 자음의 인덱스를 가져온다. */
+    int getJONGIndexofDJONG_withJONGandSIPKEY(int p_first_jong_idx, int p_second_SIPKEY_idx);
+
+    /* 초성과 입력된 키가 결합한 이중 자음의 인덱스를 가져온다. */
+    int getJONGIndexofDJONG_withCHOandSIPKEY(int p_first_cho_idx, int p_second_SIPKEY_idx);
+
+       /* 종성과 입력된 3X4키의 Rotation Key들이 이중 자음으로 결합할 수 있는지를 확인한다. */
+       int getRotationKeyCanBeDOUBLEJONG(int p_first_jong_idx, int p_second_SIPKEY_idx);
+
+//------------------ Back Space를 처리하기 위한 Automata History Stack 관련 함수 ---------------
+    /* initializeAutomataHistoryStack : Automata History Stack 을 초기화 한다. */
+    void initAutomataHistoryStack();
+
+    /* pushCurrentEnvToAutomataHistoryStack : 오토마타와 관련된 환경을 Automata History Stack 에 push 한다.*/
+    void pushEnvToAutomataHistoryStack(int p_state, MAKECODE p_tmp_makecode);
+
+    /* popFromAutomataHistoryStack : Automata 관련 전역변수 BS이전으로 복원, Stack pop */
+    void popFromAutomataHistoryStack();
+
+    /* initAutomataEnv : Automata의 환경을 초기화 한다. */
+    void initAutomataEnv();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //remove duplicate
index 13d4da4..9036aaa 100644 (file)
@@ -24,6 +24,9 @@
 
 #include "ise_lang_table.h"
 
+#include <iconv.h>
+#include "cji.h"
+
 using namespace scl;
 
 #define MVK_Shift_L 0xffe1
@@ -83,9 +86,12 @@ public :
     sclboolean on_language_selected(const sclchar *language, const sclchar *input_mode);
     sclboolean on_language_unselected(const sclchar *language, const sclchar *input_mode);
 
+    sclboolean reset_language(const sclchar *language);
+
     sclboolean flush_imengine(const sclchar *language);
     private:
         SCLEventReturnType process_key_type_char(const SclUIEventDesc&);
+        SCLEventReturnType process_key_type_user(const SclUIEventDesc&);
 };
 
 static CSDKISE ise_instance;
@@ -96,20 +102,103 @@ extern CSCLCore g_core;
 extern CONFIG_VALUES g_config_values;
 extern KEYBOARD_STATE g_keyboard_state;
 
+#define KOREAN_ENCODING_BUFFER_SIZE 256
+#define AUTOMATA_BASE_ENCODING "UCS-2"
+#define SYSTEM_OUTPUT_ENCODING "UTF8"
+
+int iconv_string(const char *from, const char *to, const char *src, char *dst, size_t inleftsize, size_t outleftsize)
+{
+    size_t dstlen;
+    size_t res;
+    iconv_t cd = (iconv_t)-1;
+
+    char *inptr;
+    char *outptr;
+
+    /* open iconv */
+    cd = iconv_open(to, from);
+    if (cd == (iconv_t)(-1)) {
+        return (int)cd;
+    }
+
+    dstlen = outleftsize;
+    inptr = (char*)src;
+    outptr = dst;
+
+    while (1) {
+        res = iconv(cd, &inptr, &inleftsize, &outptr, &outleftsize);
+        if (res == (size_t)(-1)) {
+            if (errno == EILSEQ) { /* not defined char in the table ? */
+                fprintf(stderr, "iconv_str: can't convert[%s]\n", src);
+                /* for 2-byte code incompleteness */
+                inptr++;
+                inleftsize--;
+            }
+            else if (errno == EINVAL) { /* incomplete char, need readin more codes */
+                fprintf(stderr, "iconv_str: incomplete char or shift sequence\n");
+                if (inleftsize <= 2) {
+                    *outptr = '?';
+                    outleftsize--;
+                    break;
+                }
+            }
+            *outptr = '?';
+            outptr++;
+            outleftsize--;
+            inptr++;
+            inleftsize--;
+        }
+        else break;
+    }
+    dst[dstlen - outleftsize] = '\0';
+    /* close iconv */
+    iconv_close(cd);
+    return(dstlen - outleftsize);
+}
+
+int process_korean_automata(int is_consonant, unsigned short key_index)
+{
+    MADECODE madecode = {0};
+    MAKECODE makecode = { 0 };
+    char buffer[KOREAN_ENCODING_BUFFER_SIZE] = { 0 };
+
+    makecode = CJI_GetMakeCode();
+
+    int ret = CJI_Automata(is_consonant, key_index, &madecode);
+    iconv_string(AUTOMATA_BASE_ENCODING, SYSTEM_OUTPUT_ENCODING,
+        (const char*)(madecode.ucode), buffer, madecode.size * 2, KOREAN_ENCODING_BUFFER_SIZE);
+    if (buffer[0]) {
+        ise_send_string(buffer);
+    }
+    iconv_string(AUTOMATA_BASE_ENCODING, SYSTEM_OUTPUT_ENCODING,
+        (const char*)(CJI_GetMakeCode().ucode), buffer, CJI_GetMakeCode().size * 2, KOREAN_ENCODING_BUFFER_SIZE);
+    if (buffer[0] || makecode.size > 0) {
+        ise_update_preedit_string(buffer);
+        ret = TRUE;
+    }
+
+    return ret;
+}
+
 SCLEventReturnType
 CSDKISE::process_key_type_char(const SclUIEventDesc& event_desc)
 {
-    // patch for Chinese symbol ^
-    // Chinese engine will regards ^ as ……
-    // this patch is to avoid this
     const sclchar * cur_lang = _language_manager.get_current_language();
     if (cur_lang) {
         if (0 == strcmp(cur_lang, "Chinese")) {
+            // patch for Chinese symbol ^
+            // Chinese engine will regards ^ as ……
+            // this patch is to avoid this
+
             if (event_desc.key_event == '^') {
                 ise_forward_key_event(event_desc.key_event);
                 return SCL_EVENT_DONE;
             }
         }
+        if (0 == strcmp(cur_lang, "Korean")) {
+            if (process_korean_automata(false, SIPKEY_ERROR))
+                return SCL_EVENT_DONE;
+        }
     }
     // patch for Chinese symbol ^ end
     /* If longkey symbol was pressed, let's flush the preedit buffer */
@@ -117,6 +206,47 @@ CSDKISE::process_key_type_char(const SclUIEventDesc& event_desc)
         flush_imengine(cur_lang);
     }
 
+    return SCL_EVENT_PASS_ON;
+}
+
+SCLEventReturnType
+CSDKISE::process_key_type_user(const SclUIEventDesc& event_desc)
+{
+    const sclchar * cur_lang = _language_manager.get_current_language();
+    if (cur_lang) {
+        if (0 == strcmp(cur_lang, "Korean")) {
+            typedef struct {
+                const char* key_id;
+                int sip_index;
+                bool is_consonant;
+            } CJI_key_table;
+            CJI_key_table table[] = {
+                { "SIPKEY_1", SIPKEY_IDX2, false },
+                { "SIPKEY_2", SIPKEY_IDX0, false },
+                { "SIPKEY_3", SIPKEY_IDX1, false },
+                { "SIPKEY_4", SIPKEY_IDX19, true },
+                { "SIPKEY_5", SIPKEY_IDX20, true },
+                { "SIPKEY_6", SIPKEY_IDX21, true },
+                { "SIPKEY_7", SIPKEY_IDX22, true },
+                { "SIPKEY_8", SIPKEY_IDX23, true },
+                { "SIPKEY_9", SIPKEY_IDX24, true },
+                { "SIPKEY_0", SIPKEY_IDX25, true },
+            };
+            bool found = false;
+            for (unsigned int loop = 0; loop < sizeof(table) / sizeof(CJI_key_table); loop++) {
+                if (strncmp((char*)(event_desc.key_value), table[loop].key_id,
+                    strlen(table[loop].key_id)) == 0) {
+                    found = true;
+                    if (process_korean_automata(table[loop].is_consonant, table[loop].sip_index))
+                        return SCL_EVENT_DONE;
+                }
+            }
+            if (!found) {
+                if (process_korean_automata(false, SIPKEY_ERROR))
+                    return SCL_EVENT_DONE;
+            }
+        }
+    }
 
     return SCL_EVENT_PASS_ON;
 }
@@ -131,6 +261,9 @@ SCLEventReturnType CSDKISE::on_event_key_clicked(SclUIEventDesc event_desc)
             ret = process_key_type_char(event_desc);
             break;
         case KEY_TYPE_STRING:
+            if (strcmp(_language_manager.get_current_language(), "Korean") == 0) {
+                process_korean_automata(false, SIPKEY_ERROR);
+            }
             if (event_desc.key_modifier != KEY_MODIFIER_MULTITAP_START &&
                     event_desc.key_modifier != KEY_MODIFIER_MULTITAP_REPEAT) {
                 flush_imengine(cur_lang);
@@ -138,49 +271,67 @@ SCLEventReturnType CSDKISE::on_event_key_clicked(SclUIEventDesc event_desc)
             break;
         case KEY_TYPE_MODECHANGE:
             {
+                if (strcmp(_language_manager.get_current_language(), "Korean") == 0) {
+                    process_korean_automata(false, SIPKEY_ERROR);
+                }
                 flush_imengine(cur_lang);
             }
             break;
         case KEY_TYPE_CONTROL:
-        /* Do not flush when the entered key is one of : BACKSPACE / SHIFT / CAPSLOCK / SHIFTLOCK */
-        if (event_desc.key_event != MVK_BackSpace &&
-            event_desc.key_event != MVK_Shift_L &&
-            event_desc.key_event != MVK_Caps_Lock &&
-            event_desc.key_event != MVK_Shift_Lock &&
-            event_desc.key_event != MVK_space &&
-            event_desc.key_event != MVK_Return) {
-            flush_imengine(cur_lang);
-        }
-        if (event_desc.key_event == MVK_space) {
-            if (_language_manager.get_enabled_languages_num() > 1) {
-                if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_LEFT) {
-                    /* If flick event upon space key was detected, perform a language change and don't proceed anymore */
-                    _language_manager.select_previous_language();
-                    g_keyboard_state.disable_force_latin = TRUE;
-                    ret = SCL_EVENT_DONE;
-                }
-                if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_RIGHT) {
-                    /* If flick event upon space key was detected, perform a language change and don't proceed anymore */
-                    _language_manager.select_next_language();
-                    g_keyboard_state.disable_force_latin = TRUE;
-                    ret = SCL_EVENT_DONE;
+            {
+                /* Do not flush when the entered key is one of : BACKSPACE / SHIFT / CAPSLOCK / SHIFTLOCK */
+                if (event_desc.key_event != MVK_BackSpace &&
+                    event_desc.key_event != MVK_Shift_L &&
+                    event_desc.key_event != MVK_Caps_Lock &&
+                    event_desc.key_event != MVK_Shift_Lock &&
+                    event_desc.key_event != MVK_space &&
+                    event_desc.key_event != MVK_Return) {
+                    flush_imengine(cur_lang);
                 }
-            } else {
-                if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_LEFT ||
-                    event_desc.key_modifier == KEY_MODIFIER_DIRECTION_LEFT_RETURN) {
-                        /* If flick event upon space key was detected, perform a cursor movement and don't proceed anymore */
-                        ise_send_event(MVK_Left, 0);
-                        ret = SCL_EVENT_DONE;
+                if (event_desc.key_event == MVK_space) {
+                    if (_language_manager.get_enabled_languages_num() > 1) {
+                        if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_LEFT) {
+                            /* If flick event upon space key was detected, perform a language change and don't proceed anymore */
+                            _language_manager.select_previous_language();
+                            g_keyboard_state.disable_force_latin = TRUE;
+                            ret = SCL_EVENT_DONE;
+                        }
+                        if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_RIGHT) {
+                            /* If flick event upon space key was detected, perform a language change and don't proceed anymore */
+                            _language_manager.select_next_language();
+                            g_keyboard_state.disable_force_latin = TRUE;
+                            ret = SCL_EVENT_DONE;
+                        }
+                    } else {
+                        if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_LEFT ||
+                            event_desc.key_modifier == KEY_MODIFIER_DIRECTION_LEFT_RETURN) {
+                                /* If flick event upon space key was detected, perform a cursor movement and don't proceed anymore */
+                                ise_send_event(MVK_Left, 0);
+                                ret = SCL_EVENT_DONE;
+                        }
+                        if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_RIGHT ||
+                            event_desc.key_modifier == KEY_MODIFIER_DIRECTION_RIGHT_RETURN) {
+                                /* If flick event upon space key was detected, perform a cursor movement and don't proceed anymore */
+                                ise_send_event(MVK_Right, 0);
+                                ret = SCL_EVENT_DONE;
+                        }
+                    }
                 }
-                if (event_desc.key_modifier == KEY_MODIFIER_DIRECTION_RIGHT ||
-                    event_desc.key_modifier == KEY_MODIFIER_DIRECTION_RIGHT_RETURN) {
-                        /* If flick event upon space key was detected, perform a cursor movement and don't proceed anymore */
-                        ise_send_event(MVK_Right, 0);
-                        ret = SCL_EVENT_DONE;
+                if (strcmp(_language_manager.get_current_language(), "Korean") == 0) {
+                    if (event_desc.key_event == MVK_BackSpace) {
+                        if (process_korean_automata(false, SIPKEY_BACKSPACE))
+                            ret = SCL_EVENT_DONE;
+                    }
+                    else {
+                        if (process_korean_automata(false, SIPKEY_ERROR))
+                            ret = SCL_EVENT_DONE;
+                    }
                 }
             }
-        }
-        break;
+            break;
+        case KEY_TYPE_USER:
+            ret = process_key_type_user(event_desc);
+            break;
     default:
         break;
     }
@@ -224,6 +375,7 @@ sclboolean CSDKISE::on_language_selected(const sclchar *language, const sclchar
                         g_core.set_keyboard_ise_by_uuid(get_lang_table()[loop].keyboard_ise_uuid);
                         g_core.send_imengine_event(-1, get_lang_table()[loop].keyboard_ise_uuid,
                             get_lang_table()[loop].language_command, get_lang_table()[loop].language_code);
+                        flush_imengine(language);
                     }
 
                     /* This is to update the screen only for once, not everytime we request a UI update  */
@@ -309,6 +461,23 @@ sclboolean CSDKISE::on_language_unselected(const sclchar *language, const sclcha
     return ret;
 }
 
+sclboolean CSDKISE::reset_language(const sclchar *language)
+{
+    sclboolean ret = FALSE;
+
+    if (language) {
+        sclint loop;
+        for (loop = 0; loop < get_lang_table_size(); loop++) {
+            if (strcmp(language, get_lang_table()[loop].language) == 0) {
+                flush_imengine(language);
+                ret = TRUE;
+            }
+        }
+    }
+
+    return ret;
+}
+
 static inline int get_lang_id(const sclchar* language) {
     if (language == NULL) return -1;
 
@@ -345,6 +514,9 @@ sclboolean CSDKISE::flush_imengine(const sclchar *language)
             bRet = true;
         }
     }
+    if (strcmp(_language_manager.get_current_language(), "Korean") == 0) {
+        process_korean_automata(false, SIPKEY_ERROR);
+    }
 
     return bRet;
 }