summaryrefslogtreecommitdiff
path: root/lisp/leim/quail/hangul.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/leim/quail/hangul.el')
-rw-r--r--lisp/leim/quail/hangul.el550
1 files changed, 550 insertions, 0 deletions
diff --git a/lisp/leim/quail/hangul.el b/lisp/leim/quail/hangul.el
new file mode 100644
index 00000000000..ba20d42ed8b
--- /dev/null
+++ b/lisp/leim/quail/hangul.el
@@ -0,0 +1,550 @@
+;;; hangul.el --- Korean Hangul input method
+
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
+
+;; Author: Jihyun Cho <jihyun.jo@gmail.com>
+;; Keywords: multilingual, input method, Korean, Hangul
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file is to implement the following hangul automata:
+;; - Hangul 2-Bulsik input method
+;; - Hangul 3-Bulsik final input method
+;; - Hangul 3-Bulsik 390 input method
+
+;;; Code:
+
+(require 'quail)
+(require 'hanja-util)
+
+;; Hangul double Jamo table.
+;; The format is an alist of JAMO-TYPE vs. DOUBLE-JAMO-TABLE.
+;;
+;; JAMO-TYPE is a symbol `cho' for Choseong, `jung' for Jungseong, and
+;; `jong' for Jongseong.
+;;
+;; DOUBLE-JAMO-TABLE is an alist of Jamo index vs. the vector of Jamo
+;; indies that can be combined with the car part.
+;;
+;; Jamo index is a relative index in `hangul Compatibility Jamo' area
+;; of the Unicode (i.e. 1 for U+3131).
+
+(defconst hangul-djamo-table
+ '((cho . ((1 . [1]) ; Choseong
+ (7 . [7])
+ (18 . [18])
+ (21 . [21])
+ (24 . [24])))
+ (jung . ((39 . [31 32 51]) ; Jungseong
+ (44 . [35 36 51])
+ (49 . [51])))
+ (jong . ((1 . [1 21]) ; Jongseong
+ (4 . [24 30])
+ (9 . [1 17 18 21 28 29 30])
+ (18 . [18 21])
+ (21 . [21])))))
+
+;; Hangul 2-Bulsik keymap.
+;; It converts an ASCII code A-Z, a-z, to the corresponding hangul
+;; Jamo index.
+
+(defconst hangul2-keymap
+ [17 48 26 23 7 9 30 39 33 35 31 51 49 44 32 36 18 1 4 21 37 29 24 28 43 27])
+
+;; Hangul 3-Bulsik final keymap. 3-Bulsik use full keyboard layout.
+;; Therefore, we must map all printable ASCII codes (`!' to `~')
+;; to Hangul 3-Bulsik codes.
+;; Other parts are the same as `hangul2-keymap'.
+(defconst hangul3-keymap
+ [2 183 24 15 14 8220 120 39 126 8221 43 44 41 46 74 119 30 22 18 78 83
+ 68 73 85 79 52 110 44 62 46 33 10 7 63 27 12 5 11 69 48 55 49 50 51
+ 34 45 56 57 29 16 6 13 54 3 28 20 53 26 40 58 60 61 59 42 23 79 71
+ 86 72 66 84 96 109 115 93 116 122 113 118 121 21 67 4 70 99 74 9 1
+ 101 17 37 92 47 8251])
+
+;; Hangul 3-Bulsik 390 keymap.
+;; The role is the same as `hangul3-keymap'.
+(defconst hangul390-keymap
+ [24 34 35 36 37 38 120 40 41 42 43 44 45 46 73 119 30 22 18 77 82 67 72
+ 84 78 58 110 50 61 51 63 64 7 33 11 10 27 2 47 39 56 52 53 54 49 48
+ 57 62 29 68 6 59 55 16 28 20 60 26 91 92 93 94 95 96 23 78 70 85 71
+ 65 83 90 109 115 87 116 122 113 118 121 21 66 4 69 99 73 9 1 101 17
+ 123 124 125 126])
+
+(defvar hangul-im-keymap
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\d" 'hangul-delete-backward-char)
+ (define-key map [f9] 'hangul-to-hanja-conversion)
+ (define-key map [Hangul_Hanja] 'hangul-to-hanja-conversion)
+ map)
+ "Keymap for Hangul method. It is used by all Hangul input methods.")
+
+;; Current input character buffer. Store separated hangul character.
+;; The first and second are Choseong position.
+;; The third and forth are Jungseong position.
+;; The fifth and sixth are Jongseong position.
+;; The second, forth and sixth are double Jamo position.
+(defvar hangul-queue
+ (make-vector 6 0))
+
+(defsubst notzerop (number)
+ (not (zerop number)))
+
+(defsubst alphabetp (char)
+ (or (and (>= char ?A) (<= char ?Z))
+ (and (>= char ?a) (<= char ?z))))
+
+(defun hangul-character (cho jung jong)
+ "Convert CHO, JUNG, JONG to the precomposed `Hangul Syllables' character.
+CHO, JUNG, JONG are relative indices in `Hangul Compatibility Jamo' of Unicode.
+Return a zero-length string if the conversion fails."
+ (or
+ (decode-char
+ 'ucs
+ (if (and (/= cho 0) (/= jung 0))
+ (+ #xac00
+ (* 588
+ (- cho
+ (cond ((< cho 3) 1)
+ ((< cho 5) 2)
+ ((< cho 10) 4)
+ ((< cho 20) 11)
+ (t 12))))
+ (* 28 (- jung 31))
+ (- jong
+ (cond ((< jong 8) 0)
+ ((< jong 19) 1)
+ ((< jong 25) 2)
+ (t 3))))
+ (+ #x3130
+ (cond ((/= cho 0) cho)
+ ((/= jung 0) jung)
+ ((/= jong 0) jong)))))
+ ""))
+
+(defun hangul-insert-character (&rest queues)
+ "Insert characters generated from QUEUES.
+Each queue has the same form as `hangul-queue'.
+Setup `quail-overlay' to the last character."
+ (if (and mark-active transient-mark-mode)
+ (progn
+ (delete-region (region-beginning) (region-end))
+ (deactivate-mark)))
+ (quail-delete-region)
+ (let ((first (car queues)))
+ (insert
+ (hangul-character
+ (+ (aref first 0) (hangul-djamo 'cho (aref first 0) (aref first 1)))
+ (+ (aref first 2) (hangul-djamo 'jung (aref first 2) (aref first 3)))
+ (+ (aref first 4) (hangul-djamo 'jong (aref first 4) (aref first 5))))))
+ (move-overlay quail-overlay (overlay-start quail-overlay) (point))
+ (dolist (queue (cdr queues))
+ (insert
+ (hangul-character
+ (+ (aref queue 0) (hangul-djamo 'cho (aref queue 0) (aref queue 1)))
+ (+ (aref queue 2) (hangul-djamo 'jung (aref queue 2) (aref queue 3)))
+ (+ (aref queue 4) (hangul-djamo 'jong (aref queue 4) (aref queue 5)))))
+ (move-overlay quail-overlay (1+ (overlay-start quail-overlay)) (point))))
+
+(defun hangul-djamo (jamo char1 char2)
+ "Return the double Jamo index calculated from the arguments.
+JAMO is a type of Hangul Jamo; `cho', `jung', or `jong'.
+CHAR1 and CHAR2 are Hangul Jamo indices.
+Return nil if CHAR1 and CHAR2 can not be combined."
+ (let* ((jamo (cdr (assoc jamo hangul-djamo-table)))
+ (char1 (cdr (assoc char1 jamo))))
+ (if char1
+ (let ((i (length char1)))
+ (or (catch 'found
+ (while (> i 0)
+ (if (= char2 (aref char1 (1- i)))
+ (throw 'found i))
+ (setf i (1- i))))
+ 0))
+ 0)))
+
+(defsubst hangul2-input-method-jaum (char)
+ "Store Hangul Jamo indice CHAR in `hangul-queue'.
+It is a Hangul 2-Bulsik Jaum.
+This function processes a Hangul 2-Bulsik Jaum.
+The Hangul 2-Bulsik is composed of a Jaum and a Moum.
+The Jaum can be located in a Choseong position and a Jongseong position.
+Unless the function inserts CHAR to `hangul-queue',
+commit current `hangul-queue' and then set a new `hangul-queue',
+and insert CHAR to new `hangul-queue'."
+ (if (cond ((zerop (aref hangul-queue 0))
+ (aset hangul-queue 0 char))
+ ((and (zerop (aref hangul-queue 1))
+ (zerop (aref hangul-queue 2))
+ (notzerop (hangul-djamo 'cho (aref hangul-queue 0) char)))
+ (aset hangul-queue 1 char))
+ ((and (zerop (aref hangul-queue 4))
+ (notzerop (aref hangul-queue 2))
+ (/= char 8)
+ (/= char 19)
+ (/= char 25)
+ (numberp
+ (hangul-character
+ (+ (aref hangul-queue 0)
+ (hangul-djamo
+ 'cho
+ (aref hangul-queue 0)
+ (aref hangul-queue 1)))
+ (+ (aref hangul-queue 2)
+ (hangul-djamo
+ 'jung
+ (aref hangul-queue 2)
+ (aref hangul-queue 3)))
+ char)))
+ (aset hangul-queue 4 char))
+ ((and (zerop (aref hangul-queue 5))
+ (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
+ (numberp
+ (hangul-character
+ (+ (aref hangul-queue 0)
+ (hangul-djamo
+ 'cho
+ (aref hangul-queue 0)
+ (aref hangul-queue 1)))
+ (+ (aref hangul-queue 2)
+ (hangul-djamo
+ 'jung
+ (aref hangul-queue 2)
+ (aref hangul-queue 3)))
+ (+ (aref hangul-queue 4)
+ (hangul-djamo
+ 'jong
+ (aref hangul-queue 4)
+ char)))))
+ (aset hangul-queue 5 char)))
+ (hangul-insert-character hangul-queue)
+ (hangul-insert-character hangul-queue
+ (setq hangul-queue (vector char 0 0 0 0 0)))))
+
+(defsubst hangul2-input-method-moum (char)
+ "Store Hangul Jamo indice CHAR in `hangul-queue'.
+It is a Hangul 2-Bulsik Moum.
+This function processes a Hangul 2-Bulsik Moum.
+The Moum can be located in a Jungseong position.
+Other parts are the same as a `hangul2-input-method-jaum'."
+ (if (cond ((zerop (aref hangul-queue 2))
+ (aset hangul-queue 2 char))
+ ((and (zerop (aref hangul-queue 3))
+ (zerop (aref hangul-queue 4))
+ (notzerop (hangul-djamo 'jung (aref hangul-queue 2) char)))
+ (aset hangul-queue 3 char)))
+ (hangul-insert-character hangul-queue)
+ (let ((next-char (vector 0 0 char 0 0 0)))
+ (cond ((notzerop (aref hangul-queue 5))
+ (aset next-char 0 (aref hangul-queue 5))
+ (aset hangul-queue 5 0))
+ ((notzerop (aref hangul-queue 4))
+ (aset next-char 0 (aref hangul-queue 4))
+ (aset hangul-queue 4 0)))
+ (hangul-insert-character hangul-queue
+ (setq hangul-queue next-char)))))
+
+(defsubst hangul3-input-method-cho (char)
+ "Store Hangul Jamo indice CHAR in `hangul-queue'.
+It is a Hangul 3-Bulsik Choseong.
+This function processes a Hangul 3-Bulsik Choseong.
+The Hangul 3-Bulsik is composed of a Choseong, a Jungseong and a Jongseong.
+The Choseong can be located in a Choseong position.
+Other parts are the same as a `hangul2-input-method-jaum'."
+ (if (cond ((and (zerop (aref hangul-queue 0))
+ (zerop (aref hangul-queue 4)))
+ (aset hangul-queue 0 char))
+ ((and (zerop (aref hangul-queue 1))
+ (zerop (aref hangul-queue 2))
+ (notzerop (hangul-djamo 'cho (aref hangul-queue 0) char)))
+ (aset hangul-queue 1 char)))
+ (hangul-insert-character hangul-queue)
+ (hangul-insert-character hangul-queue
+ (setq hangul-queue (vector char 0 0 0 0 0)))))
+
+(defsubst hangul3-input-method-jung (char)
+ "Store Hangul Jamo indice CHAR in `hangul-queue'.
+It is a Hangul 3-Bulsik Jungseong.
+This function processes a Hangul 3-Bulsik Jungseong.
+The Jungseong can be located in a Jungseong position.
+Other parts are the same as a `hangul3-input-method-cho'."
+ (if (cond ((and (zerop (aref hangul-queue 2))
+ (zerop (aref hangul-queue 4)))
+ (aset hangul-queue 2 char))
+ ((and (zerop (aref hangul-queue 3))
+ (notzerop (hangul-djamo 'jung (aref hangul-queue 2) char)))
+ (aset hangul-queue 3 char)))
+ (hangul-insert-character hangul-queue)
+ (hangul-insert-character hangul-queue
+ (setq hangul-queue (vector 0 0 char 0 0 0)))))
+
+(defsubst hangul3-input-method-jong (char)
+ "Store Hangul Jamo indice CHAR in `hangul-queue'.
+It is a Hangul 3-Bulsik Jongseong.
+This function processes a Hangul 3-Bulsik Jongseong.
+The Jongseong can be located in a Jongseong position.
+Other parts are the same as a `hangul3-input-method-cho'."
+ (if (cond ((and (zerop (aref hangul-queue 4))
+ (notzerop (aref hangul-queue 0))
+ (notzerop (aref hangul-queue 2))
+ (numberp
+ (hangul-character
+ (+ (aref hangul-queue 0)
+ (hangul-djamo
+ 'cho
+ (aref hangul-queue 0)
+ (aref hangul-queue 1)))
+ (+ (aref hangul-queue 2)
+ (hangul-djamo
+ 'jung
+ (aref hangul-queue 2)
+ (aref hangul-queue 3)))
+ char)))
+ (aset hangul-queue 4 char))
+ ((and (zerop (aref hangul-queue 5))
+ (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
+ (numberp
+ (hangul-character
+ (+ (aref hangul-queue 0)
+ (hangul-djamo
+ 'cho
+ (aref hangul-queue 0)
+ (aref hangul-queue 1)))
+ (+ (aref hangul-queue 2)
+ (hangul-djamo
+ 'jung
+ (aref hangul-queue 2)
+ (aref hangul-queue 3)))
+ (+ (aref hangul-queue 4)
+ (hangul-djamo
+ 'jong
+ (aref hangul-queue 4)
+ char)))))
+ (aset hangul-queue 5 char)))
+ (hangul-insert-character hangul-queue)
+ (if (zerop (apply '+ (append hangul-queue nil)))
+ (hangul-insert-character (setq hangul-queue (vector 0 0 0 0 char 0)))
+ (hangul-insert-character hangul-queue
+ (setq hangul-queue (vector 0 0 0 0 char 0))))))
+
+(defun hangul-delete-backward-char ()
+ "Delete the previous hangul character by Jaso units."
+ (interactive)
+ (let ((i 5))
+ (while (and (> i 0) (zerop (aref hangul-queue i)))
+ (setq i (1- i)))
+ (aset hangul-queue i 0))
+ (if (notzerop (apply '+ (append hangul-queue nil)))
+ (hangul-insert-character hangul-queue)
+ (delete-backward-char 1)))
+
+(defun hangul-to-hanja-conversion ()
+ "Convert the previous hangul character to the corresponding hanja character.
+When a Korean input method is off, convert the following hangul character."
+ (interactive)
+ (let ((echo-keystrokes 0)
+ delete-func
+ hanja-character)
+ (if (and (overlayp quail-overlay) (overlay-start quail-overlay))
+ (progn
+ (setq hanja-character (hangul-to-hanja-char (preceding-char)))
+ (setq delete-func (lambda () (delete-backward-char 1))))
+ (setq hanja-character (hangul-to-hanja-char (following-char)))
+ (setq delete-func (lambda () (delete-char 1))))
+ (when hanja-character
+ (funcall delete-func)
+ (insert hanja-character)
+ (setq hangul-queue (make-vector 6 0))
+ (if (and (overlayp quail-overlay) (overlay-start quail-overlay))
+ (move-overlay quail-overlay (point) (point))))))
+
+;; Support function for `hangul2-input-method'. Actually, this
+;; function handles the Hangul 2-Bulsik. KEY is an entered key code
+;; used for looking up `hangul2-keymap'."
+(defun hangul2-input-method-internal (key)
+ (let ((char (+ (aref hangul2-keymap (1- (% key 32)))
+ (cond ((or (= key ?O) (= key ?P)) 2)
+ ((or (= key ?E) (= key ?Q) (= key ?R)
+ (= key ?T) (= key ?W)) 1)
+ (t 0)))))
+ (if (< char 31)
+ (hangul2-input-method-jaum char)
+ (hangul2-input-method-moum char))))
+
+(defun hangul2-input-method (key)
+ "2-Bulsik input method."
+ (if (or buffer-read-only (not (alphabetp key)))
+ (list key)
+ (quail-setup-overlays nil)
+ (let ((input-method-function nil)
+ (echo-keystrokes 0)
+ (help-char nil))
+ (setq hangul-queue (make-vector 6 0))
+ (hangul2-input-method-internal key)
+ (unwind-protect
+ (catch 'exit-input-loop
+ (while t
+ (let* ((seq (read-key-sequence nil))
+ (cmd (lookup-key hangul-im-keymap seq))
+ key)
+ (cond ((and (stringp seq)
+ (= 1 (length seq))
+ (setq key (aref seq 0))
+ (alphabetp key))
+ (hangul2-input-method-internal key))
+ ((commandp cmd)
+ (call-interactively cmd))
+ (t
+ (setq unread-command-events (listify-key-sequence seq))
+ (throw 'exit-input-loop nil))))))
+ (quail-delete-overlays)))))
+
+;; Support function for `hangul3-input-method'. Actually, this
+;; function handles the Hangul 3-Bulsik final. KEY is an entered key
+;; code used for looking up `hangul3-keymap'."
+(defun hangul3-input-method-internal (key)
+ (let ((char (aref hangul3-keymap (- key 33))))
+ (cond ((and (> char 92) (< char 123))
+ (hangul3-input-method-cho (- char 92)))
+ ((and (> char 65) (< char 87))
+ (hangul3-input-method-jung (- char 35)))
+ ((< char 31)
+ (hangul3-input-method-jong char))
+ (t
+ (setq hangul-queue (make-vector 6 0))
+ (insert (decode-char 'ucs char))
+ (move-overlay quail-overlay (point) (point))))))
+
+(defun hangul3-input-method (key)
+ "3-Bulsik final input method."
+ (if (or buffer-read-only (< key 33) (>= key 127))
+ (list key)
+ (quail-setup-overlays nil)
+ (let ((input-method-function nil)
+ (echo-keystrokes 0)
+ (help-char nil))
+ (setq hangul-queue (make-vector 6 0))
+ (hangul3-input-method-internal key)
+ (unwind-protect
+ (catch 'exit-input-loop
+ (while t
+ (let* ((seq (read-key-sequence nil))
+ (cmd (lookup-key hangul-im-keymap seq))
+ key)
+ (cond ((and (stringp seq)
+ (= 1 (length seq))
+ (setq key (aref seq 0))
+ (and (>= key 33) (< key 127)))
+ (hangul3-input-method-internal key))
+ ((commandp cmd)
+ (call-interactively cmd))
+ (t
+ (setq unread-command-events (listify-key-sequence seq))
+ (throw 'exit-input-loop nil))))))
+ (quail-delete-overlays)))))
+
+;; Support function for `hangul390-input-method'. Actually, this
+;; function handles the Hangul 3-Bulsik 390. KEY is an entered key
+;; code used for looking up `hangul390-keymap'."
+(defun hangul390-input-method-internal (key)
+ (let ((char (aref hangul390-keymap (- key 33))))
+ (cond ((or (and (> char 86) (< char 91))
+ (and (> char 96) (< char 123)))
+ (hangul3-input-method-cho (- char (if (< char 97) 86 92))))
+ ((and (> char 64) (< char 86))
+ (hangul3-input-method-jung (- char 34)))
+ ((< char 31)
+ (hangul3-input-method-jong char))
+ (t
+ (setq hangul-queue (make-vector 6 0))
+ (insert (decode-char 'ucs char))
+ (move-overlay quail-overlay (point) (point))))))
+
+(defun hangul390-input-method (key)
+ "3-Bulsik 390 input method."
+ (if (or buffer-read-only (< key 33) (>= key 127))
+ (list key)
+ (quail-setup-overlays nil)
+ (let ((input-method-function nil)
+ (echo-keystrokes 0)
+ (help-char nil))
+ (setq hangul-queue (make-vector 6 0))
+ (hangul390-input-method-internal key)
+ (unwind-protect
+ (catch 'exit-input-loop
+ (while t
+ (let* ((seq (read-key-sequence nil))
+ (cmd (lookup-key hangul-im-keymap seq))
+ key)
+ (cond ((and (stringp seq)
+ (= 1 (length seq))
+ (setq key (aref seq 0))
+ (and (>= key 33) (< key 127)))
+ (hangul390-input-method-internal key))
+ ((commandp cmd)
+ (call-interactively cmd))
+ (t
+ (setq unread-command-events (listify-key-sequence seq))
+ (throw 'exit-input-loop nil))))))
+ (quail-delete-overlays)))))
+
+;; Text shown by describe-input-method. Set to a proper text by
+;; hangul-input-method-activate.
+(defvar hangul-input-method-help-text nil)
+(make-variable-buffer-local 'hangul-input-method-help-text)
+
+;;;###autoload
+(defun hangul-input-method-activate (input-method func help-text &rest args)
+ "Activate Hangul input method INPUT-METHOD.
+FUNC is a function to handle input key.
+HELP-TEXT is a text set in `hangul-input-method-help-text'."
+ (setq deactivate-current-input-method-function 'hangul-input-method-deactivate
+ describe-current-input-method-function 'hangul-input-method-help
+ hangul-input-method-help-text help-text)
+ (quail-delete-overlays)
+ (if (eq (selected-window) (minibuffer-window))
+ (add-hook 'minibuffer-exit-hook 'quail-exit-from-minibuffer))
+ (set (make-local-variable 'input-method-function) func))
+
+(defun hangul-input-method-deactivate ()
+ "Deactivate the current Hangul input method."
+ (interactive)
+ (unwind-protect
+ (progn
+ (quail-hide-guidance)
+ (quail-delete-overlays)
+ (setq describe-current-input-method-function nil))
+ (kill-local-variable 'input-method-function)))
+
+(define-obsolete-function-alias
+ 'hangul-input-method-inactivate
+ 'hangul-input-method-deactivate "24.3")
+
+(defun hangul-input-method-help ()
+ "Describe the current Hangul input method."
+ (interactive)
+ (with-output-to-temp-buffer "*Help*"
+ (princ hangul-input-method-help-text)))
+
+(provide 'hangul)
+
+;; Local Variables:
+;; generated-autoload-load-name: "quail/hangul"
+;; End:
+
+;;; hangul.el ends here