Add arch tagline
[emacs.git] / leim / quail / hangul.el
blob1792fad3bb196bc174aef96702f6de60ed709168
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/>.
21 ;;; Commentary:
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
28 ;;; Code:
30 (require 'quail)
31 (require 'cl)
32 (require 'hanja-util)
34 ;; Hangul double jamo table.
35 ;; NEED COMMENT. What is the car and cdr part?
36 (defconst hangul-djamo-table
37 '((cho . ((1 . [1])
38 (7 . [7])
39 (18 . [18])
40 (21 . [21])
41 (24 . [24])))
42 (jung . ((39 . [31 32 51])
43 (44 . [35 36 51])
44 (49 . [51])))
45 (jong . ((1 . [1 21])
46 (4 . [24 30])
47 (9 . [1 17 18 21 28 29 30])
48 (18 . [18 21])
49 (21 . [21])))))
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
75 123 124 125 126])
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)
81 map)
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".
88 (defvar hangul-queue
89 (make-vector 6 0))
91 (defsubst notzerop (number)
92 (not (zerop 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"
102 ;; of elisp info.
104 (decode-char
105 'ucs
106 (if (and (/= cho 0) (/= jung 0))
107 (+ #xac00
108 (* 588
109 (- cho
110 (cond ((< cho 3) 1)
111 ((< cho 5) 2)
112 ((< cho 10) 4)
113 ((< cho 20) 11)
114 (t 12))))
115 (* 28 (- jung 31))
116 (- jong
117 (cond ((< jong 8) 0)
118 ((< jong 19) 1)
119 ((< jong 25) 2)
120 (t 3))))
121 (+ #x3130
122 (cond ((/= cho 0) cho)
123 ((/= jung 0) jung)
124 ((/= jong 0) jong)))))
125 ""))
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)
130 (progn
131 (delete-region (region-beginning) (region-end))
132 (deactivate-mark)))
133 (quail-delete-region)
134 (let ((first (car queues)))
135 (insert
136 (hangul-character
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))
142 (insert
143 (hangul-character
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"
153 ;; of elisp info.
154 (let* ((jamo (cdr (assoc jamo hangul-djamo-table)))
155 (char1 (cdr (assoc char1 jamo))))
156 (if char1
157 (let ((i (length char1)))
158 (or (catch 'found
159 (while (> i 0)
160 (if (= char2 (aref char1 (1- i)))
161 (throw 'found i))
162 (setf i (1- i))))
164 0)))
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))
181 (/= char 8)
182 (/= char 19)
183 (/= char 25)
184 (numberp
185 (hangul-character
186 (+ (aref hangul-queue 0)
187 (hangul-djamo
188 'cho
189 (aref hangul-queue 0)
190 (aref hangul-queue 1)))
191 (+ (aref hangul-queue 2)
192 (hangul-djamo
193 'jung
194 (aref hangul-queue 2)
195 (aref hangul-queue 3)))
196 char)))
197 (aset hangul-queue 4 char))
198 ((and (zerop (aref hangul-queue 5))
199 (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
200 (numberp
201 (hangul-character
202 (+ (aref hangul-queue 0)
203 (hangul-djamo
204 'cho
205 (aref hangul-queue 0)
206 (aref hangul-queue 1)))
207 (+ (aref hangul-queue 2)
208 (hangul-djamo
209 'jung
210 (aref hangul-queue 2)
211 (aref hangul-queue 3)))
212 (+ (aref hangul-queue 4)
213 (hangul-djamo
214 'jong
215 (aref hangul-queue 4)
216 char)))))
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))
279 (numberp
280 (hangul-character
281 (+ (aref hangul-queue 0)
282 (hangul-djamo
283 'cho
284 (aref hangul-queue 0)
285 (aref hangul-queue 1)))
286 (+ (aref hangul-queue 2)
287 (hangul-djamo
288 'jung
289 (aref hangul-queue 2)
290 (aref hangul-queue 3)))
291 char)))
292 (aset hangul-queue 4 char))
293 ((and (zerop (aref hangul-queue 5))
294 (notzerop (hangul-djamo 'jong (aref hangul-queue 4) char))
295 (numberp
296 (hangul-character
297 (+ (aref hangul-queue 0)
298 (hangul-djamo
299 'cho
300 (aref hangul-queue 0)
301 (aref hangul-queue 1)))
302 (+ (aref hangul-queue 2)
303 (hangul-djamo
304 'jung
305 (aref hangul-queue 2)
306 (aref hangul-queue 3)))
307 (+ (aref hangul-queue 4)
308 (hangul-djamo
309 'jong
310 (aref hangul-queue 4)
311 char)))))
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."
321 (interactive)
322 (let ((i 5))
323 (while (and (> i 0) (zerop (aref hangul-queue i)))
324 (setq i (1- 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."
332 (interactive)
333 (let ((echo-keystrokes 0)
334 delete-func
335 hanja-character)
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)
349 (t 0)))))
350 (if (< char 31)
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)))
357 (list key)
358 (quail-setup-overlays nil)
359 (let ((input-method-function nil)
360 (echo-keystrokes 0)
361 (help-char nil))
362 (setq hangul-queue (make-vector 6 0))
363 (hangul2-input-method-internal key)
364 (unwind-protect
365 (catch 'exit-input-loop
366 (while t
367 (let* ((seq (read-key-sequence nil))
368 (cmd (lookup-key hangul-im-keymap seq))
369 key)
370 (cond ((and (stringp seq)
371 (= 1 (length seq))
372 (setq key (aref seq 0))
373 (alphabetp key))
374 (hangul2-input-method-internal key))
375 ((commandp cmd)
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)))
389 ((< char 31)
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))
399 (list key)
400 (quail-setup-overlays nil)
401 (let ((input-method-function nil)
402 (echo-keystrokes 0)
403 (help-char nil))
404 (setq hangul-queue (make-vector 6 0))
405 (hangul3-input-method-internal key)
406 (unwind-protect
407 (catch 'exit-input-loop
408 (while t
409 (let* ((seq (read-key-sequence nil))
410 (cmd (lookup-key hangul-im-keymap seq))
411 key)
412 (cond ((and (stringp seq)
413 (= 1 (length seq))
414 (setq key (aref seq 0))
415 (and (>= key 33) (< key 127)))
416 (hangul3-input-method-internal key))
417 ((commandp cmd)
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)))
432 ((< char 31)
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))
442 (list key)
443 (quail-setup-overlays nil)
444 (let ((input-method-function nil)
445 (echo-keystrokes 0)
446 (help-char nil))
447 (setq hangul-queue (make-vector 6 0))
448 (hangul390-input-method-internal key)
449 (unwind-protect
450 (catch 'exit-input-loop
451 (while t
452 (let* ((seq (read-key-sequence nil))
453 (cmd (lookup-key hangul-im-keymap seq))
454 key)
455 (cond ((and (stringp seq)
456 (= 1 (length seq))
457 (setq key (aref seq 0))
458 (and (>= key 33) (< key 127)))
459 (hangul390-input-method-internal key))
460 ((commandp cmd)
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."
486 (interactive)
487 (unwind-protect
488 (progn
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."
496 (interactive)
497 (with-output-to-temp-buffer "*Help*"
498 (princ hangul-input-method-help-text)))
500 (provide 'hangul)
502 ;; arch-tag: 26bc93fc-64ee-4fb1-b26d-22220d132dbe
503 ;;; hangul.el ends here