1 ;;; hangul.el --- Korean Hangul input method
3 ;; Author: Jihyun Cho <jihyun.jo@gmail.com>
4 ;; Keywords: multilingual, input method, Korean, Hangul
6 ;; This file is part of GNU Emacs.
8 ;; GNU Emacs is free software: you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
13 ;; GNU Emacs is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23 ;; This file is to implement the following hangul automata:
24 ;; - Hangul 2-Bulsik input method
25 ;; - Hangul 3-Bulsik final input method
26 ;; - Hangul 3-Bulsik 390 input method
34 ;; Hangul double jamo table.
35 ;; NEED COMMENT. What is the car and cdr part?
36 (defconst hangul-djamo-table
42 (jung . ((39 . [31 32 51])
47 (9 . [1 17 18 21 28 29 30])
51 ;; Hangul 2-Bulsik keymap.
52 ;; This table has Hangul Jamo index.
53 ;; NEED COMMENT. What is "Hangul Jamo index"?
54 (defconst hangul2-keymap
55 [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])
57 ;; Hangul 3-Bulsik final keymap. 3-Bulsik use full keyboard layout.
58 ;; Therefore, We must assign all ASCII codes except control codes
59 ;; to Hangul 3-Bulsik codes.
60 ;; NEED COMMENT. What are these numbers?
61 (defconst hangul3-keymap
62 [2 183 24 15 14 8220 120 39 126 8221 43 44 41 46 74 119 30 22 18 78 83
63 68 73 85 79 52 110 44 62 46 33 10 7 63 27 12 5 11 69 48 55 49 50 51
64 34 45 56 57 29 16 6 13 54 3 28 20 53 26 40 58 60 61 59 42 23 79 71
65 86 72 66 84 96 109 115 93 116 122 113 118 121 21 67 4 70 99 74 9 1
66 101 17 37 92 47 8251])
68 ;; Hangul 3-Bulsik 390 keymap.
69 ;; NEED COMMENT. What are these numbers?
70 (defconst hangul390-keymap
71 [24 34 35 36 37 38 120 40 41 42 43 44 45 46 73 119 30 22 18 77 82 67 72
72 84 78 58 110 50 61 51 63 64 7 33 11 10 27 2 47 39 56 52 53 54 49 48
73 57 62 29 68 6 59 55 16 28 20 60 26 91 92 93 94 95 96 23 78 70 85 71
74 65 83 90 109 115 87 116 122 113 118 121 21 66 4 69 99 73 9 1 101 17
77 (defvar hangul-im-keymap
78 (let ((map (make-sparse-keymap)))
79 (define-key map "\d" 'hangul-delete-backward-char)
80 (define-key map [f9] 'hangul-to-hanja-conversion)
82 "Keymap for Hangul method. It is using all Hangul input method.")
84 ;; Current input character buffer. Store separated hangul character.
85 ;; First and second index of vector stored "Choseong".
86 ;; Third and forth index of vector stored "Jungseong".
87 ;; Fifth and sixth index of vector stored "Jongseong".
91 (defsubst notzerop (number)
94 (defsubst alphabetp (char)
95 (or (and (>= char ?A) (<= char ?Z))
96 (and (>= char ?a) (<= char ?z))))
98 (defun hangul-character (cho jung jong)
99 "Choseong, Jungseong, and Jongseong which are contained Hangul Compatibility Jamo area
100 are transformed hangul character in Hangul Syllables area."
101 ;; NEED ADJUSTMENT. Please read the section "Documentation Basics"
106 (if (and (/= cho 0) (/= jung 0))
122 (cond ((/= cho 0) cho)
124 ((/= jong 0) jong)))))
127 (defun hangul-insert-character (&rest queues)
128 "Insert each QUEUES. Then setup overlay last inserted character."
129 (if (and mark-active transient-mark-mode)
131 (delete-region (region-beginning) (region-end))
133 (quail-delete-region)
134 (let ((first (car queues)))
137 (+ (aref first 0) (hangul-djamo 'cho (aref first 0) (aref first 1)))
138 (+ (aref first 2) (hangul-djamo 'jung (aref first 2) (aref first 3)))
139 (+ (aref first 4) (hangul-djamo 'jong (aref first 4) (aref first 5))))))
140 (move-overlay quail-overlay (overlay-start quail-overlay) (point))
141 (dolist (queue (cdr queues))
144 (+ (aref queue 0) (hangul-djamo 'cho (aref queue 0) (aref queue 1)))
145 (+ (aref queue 2) (hangul-djamo 'jung (aref queue 2) (aref queue 3)))
146 (+ (aref queue 4) (hangul-djamo 'jong (aref queue 4) (aref queue 5)))))
147 (move-overlay quail-overlay (1+ (overlay-start quail-overlay)) (point))))
149 (defun hangul-djamo (jamo char1 char2)
150 "If CHAR1 and CHAR2 are able to combine,
151 this function returns double jamo index."
152 ;; NEED ADJUSTMENT. Please read the section "Documentation Basics"
154 (let* ((jamo (cdr (assoc jamo hangul-djamo-table)))
155 (char1 (cdr (assoc char1 jamo))))
157 (let ((i (length char1)))
160 (if (= char2 (aref char1 (1- i)))
166 ;; NEED ADJUSTMENT. The following 5 have exactly the same docstring.
167 ;; How are they different?
169 (defsubst hangul2-input-method-jaum (char)
170 "CHAR is putted in hangul-queue.
171 Unless the function insert CHAR to current input queue,
172 commit current character and then start next character."
173 (if (cond ((zerop (aref hangul-queue 0))
174 (aset hangul-queue 0 char))
175 ((and (zerop (aref hangul-queue 1))
176 (zerop (aref hangul-queue 2))
177 (notzerop (hangul-djamo 'cho (aref hangul-queue 0) char)))
178 (aset hangul-queue 1 char))
179 ((and (zerop (aref hangul-queue 4))
180 (notzerop (aref hangul-queue 2))
186 (+ (aref hangul-queue 0)
189 (aref hangul-queue 0)
190 (aref hangul-queue 1)))
191 (+ (aref hangul-queue 2)
194 (aref hangul-queue 2)
195 (aref hangul-queue 3)))
197 (aset hangul-queue 4 char))
198 ((and (zerop (aref hangul-queue 5))
199 (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
202 (+ (aref hangul-queue 0)
205 (aref hangul-queue 0)
206 (aref hangul-queue 1)))
207 (+ (aref hangul-queue 2)
210 (aref hangul-queue 2)
211 (aref hangul-queue 3)))
212 (+ (aref hangul-queue 4)
215 (aref hangul-queue 4)
217 (aset hangul-queue 5 char)))
218 (hangul-insert-character hangul-queue)
219 (hangul-insert-character hangul-queue
220 (setq hangul-queue (vector char 0 0 0 0 0)))))
222 (defsubst hangul2-input-method-moum (char)
223 "CHAR is putted in hangul-queue.
224 Unless the function insert CHAR to current input queue,
225 commit current character and then start next character."
226 (if (cond ((zerop (aref hangul-queue 2))
227 (aset hangul-queue 2 char))
228 ((and (zerop (aref hangul-queue 3))
229 (zerop (aref hangul-queue 4))
230 (notzerop (hangul-djamo 'jung (aref hangul-queue 2) char)))
231 (aset hangul-queue 3 char)))
232 (hangul-insert-character hangul-queue)
233 (let ((next-char (vector 0 0 char 0 0 0)))
234 (cond ((notzerop (aref hangul-queue 5))
235 (aset next-char 0 (aref hangul-queue 5))
236 (aset hangul-queue 5 0))
237 ((notzerop (aref hangul-queue 4))
238 (aset next-char 0 (aref hangul-queue 4))
239 (aset hangul-queue 4 0)))
240 (hangul-insert-character hangul-queue
241 (setq hangul-queue next-char)))))
243 (defsubst hangul3-input-method-cho (char)
244 "CHAR is putted in hangul-queue.
245 Unless the function insert CHAR to current input queue,
246 commit current character and then start next character."
247 (if (cond ((and (zerop (aref hangul-queue 0))
248 (zerop (aref hangul-queue 4)))
249 (aset hangul-queue 0 char))
250 ((and (zerop (aref hangul-queue 1))
251 (zerop (aref hangul-queue 2))
252 (notzerop (hangul-djamo 'cho (aref hangul-queue 0) char)))
253 (aset hangul-queue 1 char)))
254 (hangul-insert-character hangul-queue)
255 (hangul-insert-character hangul-queue
256 (setq hangul-queue (vector char 0 0 0 0 0)))))
258 (defsubst hangul3-input-method-jung (char)
259 "CHAR is putted in hangul-queue.
260 Unless the function insert CHAR to current input queue,
261 commit current character and then start next character."
262 (if (cond ((and (zerop (aref hangul-queue 2))
263 (zerop (aref hangul-queue 4)))
264 (aset hangul-queue 2 char))
265 ((and (zerop (aref hangul-queue 3))
266 (notzerop (hangul-djamo 'jung (aref hangul-queue 2) char)))
267 (aset hangul-queue 3 char)))
268 (hangul-insert-character hangul-queue)
269 (hangul-insert-character hangul-queue
270 (setq hangul-queue (vector 0 0 char 0 0 0)))))
272 (defsubst hangul3-input-method-jong (char)
273 "CHAR is putted in hangul-queue.
274 Unless the function insert CHAR to current input queue,
275 commit current character and then start next character."
276 (if (cond ((and (zerop (aref hangul-queue 4))
277 (notzerop (aref hangul-queue 0))
278 (notzerop (aref hangul-queue 2))
281 (+ (aref hangul-queue 0)
284 (aref hangul-queue 0)
285 (aref hangul-queue 1)))
286 (+ (aref hangul-queue 2)
289 (aref hangul-queue 2)
290 (aref hangul-queue 3)))
292 (aset hangul-queue 4 char))
293 ((and (zerop (aref hangul-queue 5))
294 (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
297 (+ (aref hangul-queue 0)
300 (aref hangul-queue 0)
301 (aref hangul-queue 1)))
302 (+ (aref hangul-queue 2)
305 (aref hangul-queue 2)
306 (aref hangul-queue 3)))
307 (+ (aref hangul-queue 4)
310 (aref hangul-queue 4)
312 (aset hangul-queue 6 char)))
313 (hangul-insert-character hangul-queue)
314 (if (zerop (apply '+ (append hangul-queue nil)))
315 (hangul-insert-character (setq hangul-queue (vector 0 0 0 0 char 0)))
316 (hangul-insert-character hangul-queue
317 (setq hangul-queue (vector 0 0 0 0 char 0))))))
319 (defun hangul-delete-backward-char ()
320 "Backward delete command for hangul. It deletes a hangul character by jaso units."
323 (while (and (> i 0) (zerop (aref hangul-queue i)))
325 (aset hangul-queue i 0))
326 (if (notzerop (apply '+ (append hangul-queue nil)))
327 (hangul-insert-character hangul-queue)
328 (delete-backward-char 1)))
330 (defun hangul-to-hanja-conversion ()
331 "This function converts a hangul character to a hanja character."
333 (let ((echo-keystrokes 0)
336 (setq hanja-character (hangul-to-hanja-char (preceding-char)))
337 (when hanja-character
338 (delete-backward-char 1)
339 (insert hanja-character)
340 (setq hangul-queue (make-vector 6 0))
341 (move-overlay quail-overlay (point) (point)))))
343 ;; NEED COMMENT. What is KEY?
344 (defun hangul2-input-method-internal (key)
345 (let ((char (+ (aref hangul2-keymap (1- (% key 32)))
346 (cond ((or (= key ?O) (= key ?P)) 2)
347 ((or (= key ?E) (= key ?Q) (= key ?R)
348 (= key ?T) (= key ?W)) 1)
351 (hangul2-input-method-jaum char)
352 (hangul2-input-method-moum char))))
354 (defun hangul2-input-method (key)
355 "2-Bulsik input method"
356 (if (or buffer-read-only (not (alphabetp key)))
358 (quail-setup-overlays nil)
359 (let ((input-method-function nil)
362 (setq hangul-queue (make-vector 6 0))
363 (hangul2-input-method-internal key)
365 (catch 'exit-input-loop
367 (let* ((seq (read-key-sequence nil))
368 (cmd (lookup-key hangul-im-keymap seq))
370 (cond ((and (stringp seq)
372 (setq key (aref seq 0))
374 (hangul2-input-method-internal key))
376 (call-interactively cmd))
378 (setq unread-command-events (listify-key-sequence seq))
379 (throw 'exit-input-loop nil))))))
380 (quail-delete-overlays)))))
382 ;; NEED COMMENT. What is KEY?
383 (defun hangul3-input-method-internal (key)
384 (let ((char (aref hangul3-keymap (- key 33))))
385 (cond ((and (> char 92) (< char 123))
386 (hangul3-input-method-cho (- char 92)))
387 ((and (> char 65) (< char 87))
388 (hangul3-input-method-jung (- char 35)))
390 (hangul3-input-method-jong char))
392 (setq hangul-queue (make-vector 6 0))
393 (insert (decode-char 'ucs char))
394 (move-overlay quail-overlay (point) (point))))))
396 (defun hangul3-input-method (key)
397 "3-Bulsik final input method"
398 (if (or buffer-read-only (< key 33) (>= key 127))
400 (quail-setup-overlays nil)
401 (let ((input-method-function nil)
404 (setq hangul-queue (make-vector 6 0))
405 (hangul3-input-method-internal key)
407 (catch 'exit-input-loop
409 (let* ((seq (read-key-sequence nil))
410 (cmd (lookup-key hangul-im-keymap seq))
412 (cond ((and (stringp seq)
414 (setq key (aref seq 0))
415 (and (>= key 33) (< key 127)))
416 (hangul3-input-method-internal key))
418 (call-interactively cmd))
420 (setq unread-command-events (listify-key-sequence seq))
421 (throw 'exit-input-loop nil))))))
422 (quail-delete-overlays)))))
424 ;; NEED COMMENT. What is KEY?
425 (defun hangul390-input-method-internal (key)
426 (let ((char (aref hangul390-keymap (- key 33))))
427 (cond ((or (and (> char 86) (< char 91))
428 (and (> char 96) (< char 123)))
429 (hangul3-input-method-cho (- char (if (< char 97) 86 92))))
430 ((and (> char 64) (< char 86))
431 (hangul3-input-method-jung (- char 34)))
433 (hangul3-input-method-jong char))
435 (setq hangul-queue (make-vector 6 0))
436 (insert (decode-char 'ucs char))
437 (move-overlay quail-overlay (point) (point))))))
439 (defun hangul390-input-method (key)
440 "3-Bulsik 390 input method"
441 (if (or buffer-read-only (< key 33) (>= key 127))
443 (quail-setup-overlays nil)
444 (let ((input-method-function nil)
447 (setq hangul-queue (make-vector 6 0))
448 (hangul390-input-method-internal key)
450 (catch 'exit-input-loop
452 (let* ((seq (read-key-sequence nil))
453 (cmd (lookup-key hangul-im-keymap seq))
455 (cond ((and (stringp seq)
457 (setq key (aref seq 0))
458 (and (>= key 33) (< key 127)))
459 (hangul390-input-method-internal key))
461 (call-interactively cmd))
463 (setq unread-command-events (listify-key-sequence seq))
464 (throw 'exit-input-loop nil))))))
465 (quail-delete-overlays)))))
467 ;; Text shown by describe-input-method. Set to a proper text by
468 ;; hangul-input-method-activate.
469 (defvar hangul-input-method-help-text nil)
470 (make-variable-buffer-local 'hangul-input-method-help-text)
472 (defun hangul-input-method-activate (input-method func help-text &rest args)
473 "Activate Hangul input method INPUT-METHOD.
474 FUNC is a function to handle input key.
475 HELP-TEXT is a text set in `hangul-input-method-help-text'."
476 (setq inactivate-current-input-method-function 'hangul-input-method-inactivate
477 describe-current-input-method-function 'hangul-input-method-help
478 hangul-input-method-help-text help-text)
479 (quail-delete-overlays)
480 (if (eq (selected-window) (minibuffer-window))
481 (add-hook 'minibuffer-exit-hook 'quail-exit-from-minibuffer))
482 (set (make-local-variable 'input-method-function) func))
484 (defun hangul-input-method-inactivate ()
485 "Inactivate the current Hangul input method."
489 (quail-hide-guidance)
490 (quail-delete-overlays)
491 (setq describe-current-input-method-function nil))
492 (kill-local-variable 'input-method-function)))
494 (defun hangul-input-method-help ()
495 "Describe the current Hangul input method."
497 (with-output-to-temp-buffer "*Help*"
498 (princ hangul-input-method-help-text)))
502 ;; arch-tag: 26bc93fc-64ee-4fb1-b26d-22220d132dbe
503 ;;; hangul.el ends here