e633d02eb937e2093391eb04f68a290e8213c7f2
[bpt/emacs.git] / leim / quail / lrt.el
1 ;;; quail/lrt.el --- Quail package for inputting Lao characters by LRT method
2
3 ;; Copyright (C) 1997 Electrotechnical Laboratory, JAPAN.
4 ;; Licensed to the Free Software Foundation.
5
6 ;; Keywords: multilingual, input method, Lao, LRT.
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Code:
26
27 (require 'quail)
28 (require 'lao-util)
29
30 ;; LRT (Lao Roman Transcription) input method accepts the following
31 ;; key sequence:
32 ;; consonant [+ semi-vowel-sign-lo ] + vowel [+ maa-sakod ] [+ tone-mark ]
33
34 (eval-and-compile
35
36 ;; Upper vowels and tone-marks are put on the letter.
37 ;; Semi-vowel-sign-lo and lower vowels are put under the letter.
38 (defconst lrt-single-consonant-table
39 `(("k" . ?\e(1!\e(B)
40 ("kh" . ?\e(1"\e(B)
41 ("qh" . ?\e(1$\e(B)
42 ("ng" . ?\e(1'\e(B)
43 ("j" . ?\e(1(\e(B)
44 ("s" . ?\e(1J\e(B)
45 ("x" . ?\e(1*\e(B)
46 ("y" . ?\e(1-\e(B)
47 ("d" . ?\e(14\e(B)
48 ("t" . ?\e(15\e(B)
49 ("th" . ?\e(16\e(B)
50 ("dh" . ?\e(17\e(B)
51 ("n" . ?\e(19\e(B)
52 ("b" . ?\e(1:\e(B)
53 ("p" . ?\e(1;\e(B)
54 ("hp" . ?\e(1<\e(B)
55 ("fh" . ?\e(1=\e(B)
56 ("ph" . ?\e(1>\e(B)
57 ("f" . ?\e(1?\e(B)
58 ("m" . ?\e(1A\e(B)
59 ("gn" . ?\e(1B\e(B)
60 ("l" . ?\e(1E\e(B)
61 ("r" . ?\e(1C\e(B)
62 ("v" . ?\e(1G\e(B)
63 ("w" . ?\e(1G\e(B)
64 ("hh" . ?\e(1K\e(B)
65 ("O" . ?\e(1M\e(B)
66 ("h" . ?\e(1N\e(B)
67 ("nh" . ?\e(1|\e(B)
68 ("mh" . ?\e(1}\e(B)
69 ("lh" . "\e0\e(1K\\e1\e(B")
70 ))
71
72 ;; Semi-vowel-sign-lo is put under the first letter.
73 ;; Lower vowels are put under the last letter.
74 ;; Upper vowels and tone-marks are put on the last letter.
75 (defconst lrt-double-consonant-table
76 '(("ngh" . "\e(1K'\e(B")
77 ("yh" . "\e(1K]\e(B")
78 ("wh" . "\e(1KG\e(B")
79 ("hl" . "\e(1KE\e(B")
80 ("hy" . "\e(1K-\e(B")
81 ("hn" . "\e(1K9\e(B")
82 ("hm" . "\e(1KA\e(B")
83 ))
84
85 (defconst lrt-semi-vowel-sign-lo
86 '("r" . ?\e(1\\e(B))
87
88 (defconst lrt-vowel-table
89 '(("a" "\e(1P\e(B" (0 ?\e(1P\e(B) (0 ?\e(1Q\e(B))
90 ("ar" "\e(1R\e(B" (0 ?\e(1R\e(B))
91 ("i" "\e(1T\e(B" (0 ?\e(1T\e(B))
92 ("ii" "\e(1U\e(B" (0 ?\e(1U\e(B))
93 ("eu" "\e(1V\e(B" (0 ?\e(1V\e(B))
94 ("ur" "\e(1W\e(B" (0 ?\e(1W\e(B))
95 ("u" "\e(1X\e(B" (0 ?\e(1X\e(B))
96 ("uu" "\e(1Y\e(B" (0 ?\e(1Y\e(B))
97 ("e" "\e(1`\e(B \e(1P\e(B" (?\e(1`\e(B 0 ?\e(1P\e(B) (?\e(1`\e(B 0 ?\e(1Q\e(B))
98 ("ee" "\e(1`\e(B" (?\e(1`\e(B 0))
99 ("ae" "\e(1a\e(B \e(1P\e(B" (?\e(1a\e(B 0 ?\e(1P\e(B) (?\e(1a\e(B 0 ?\e(1Q\e(B))
100 ("aa" "\e(1a\e(B" (?\e(1a\e(B 0))
101 ("o" "\e(1b\e(B \e(1P\e(B" (?\e(1b\e(B 0 ?\e(1P\e(B) (0 ?\e(1[\e(B) (?\e(1-\e(B ?\e(1b\e(B 0 ?\e(1Q\e(B) (?\e(1G\e(B ?\e(1b\e(B 0 ?\e(1Q\e(B))
102 ("oo" "\e(1b\e(B" (?\e(1b\e(B 0))
103 ("oe" "\e(1`\e(B \e(1RP\e(B" (?\e(1`\e(B 0 ?\e(1R\e(B ?\e(1P\e(B) (0 ?\e(1Q\e(B ?\e(1M\e(B))
104 ("or" "\e(1m\e(B" (0 ?\e(1m\e(B) (0 ?\e(1M\e(B))
105 ("er" "\e(1`\e(B \e(1T\e(B" (?\e(1`\e(B 0 ?\e(1T\e(B))
106 ("ir" "\e(1`\e(B \e(1U\e(B" (?\e(1`\e(B 0 ?\e(1U\e(B))
107 ("ua" "\e(1[GP\e(B" (0 ?\e(1[\e(B ?\e(1G\e(B ?\e(1P\e(B) (0 ?\e(1Q\e(B ?\e(1G\e(B))
108 ("uaa" "\e(1[G\e(B" (0 ?\e(1[\e(B ?\e(1G\e(B) (0 ?\e(1G\e(B))
109 ("ie" "\e(1`Q]P\e(B" (?\e(1`\e(B 0 ?\e(1Q\e(B ?\e(1]\e(B ?\e(1P\e(B) (0 ?\e(1Q\e(B ?\e(1]\e(B))
110 ("ia" "\e(1`Q]\e(B" (?\e(1`\e(B 0 ?\e(1Q\e(B ?\e(1]\e(B) (0 ?\e(1]\e(B))
111 ("ea" "\e(1`VM\e(B" (?\e(1`\e(B 0 ?\e(1V\e(B ?\e(1M\e(B))
112 ("eaa" "\e(1`WM\e(B" (?\e(1`\e(B 0 ?\e(1W\e(B ?\e(1M\e(B))
113 ("ai" "\e(1d\e(B" (?\e(1d\e(B 0))
114 ("ei" "\e(1c\e(B" (?\e(1c\e(B 0))
115 ("ao" "\e(1`[R\e(B" (?\e(1`\e(B 0 ?\e(1[\e(B ?\e(1R\e(B))
116 ("aM" "\e(1S\e(B" (0 ?\e(1S\e(B))))
117
118 ;; Maa-sakod is put at the tail.
119 (defconst lrt-maa-sakod-table
120 '((?k . ?\e(1!\e(B)
121 (?g . ?\e(1'\e(B)
122 (?y . ?\e(1-\e(B)
123 (?d . ?\e(14\e(B)
124 (?n . ?\e(19\e(B)
125 (?b . ?\e(1:\e(B)
126 (?m . ?\e(1A\e(B)
127 (?v . ?\e(1G\e(B)
128 (?w . ?\e(1G\e(B)
129 ))
130
131 (defconst lrt-tone-mark-table
132 '(("'" . ?\e(1h\e(B)
133 ("\"" . ?\e(1i\e(B)
134 ("^" . ?\e(1j\e(B)
135 ("+" . ?\e(1k\e(B)
136 ("~" . ?\e(1l\e(B)))
137
138 ;; Return list of composing patterns for normal (without maa-sakod)
139 ;; key sequence and with-maa-sakod key sequence starting with single
140 ;; consonant C and optional SEMI-VOWEL.
141 (defun lrt-composing-pattern-single-c (c semi-vowel vowel-pattern)
142 (let* ((patterns (copy-sequence vowel-pattern))
143 (tail patterns)
144 place)
145 ;; Embed C and SEMI-VOWEL (if any) at the place of 0.
146 (while tail
147 ;; At first, make a copy.
148 (setcar tail (copy-sequence (car tail)))
149 ;; Then, do embedding.
150 (setq place (memq 0 (car tail)))
151 (setcar place c)
152 (if semi-vowel
153 (setcdr place (cons semi-vowel (cdr place))))
154 (setq tail (cdr tail)))
155 patterns))
156
157 ;; Return list of composing patterns for normal (without maa-sakod)
158 ;; key sequence and with-maa-sakod key sequence starting with double
159 ;; consonant STR and optional SEMI-VOWEL.
160 (defun lrt-composing-pattern-double-c (str semi-vowel vowel-pattern)
161 (let* ((patterns (copy-sequence vowel-pattern))
162 (tail patterns)
163 (chars (string-to-list
164 (if (= (chars-in-string str) 1)
165 (decompose-string str)
166 str)))
167 place)
168 ;; Embed C and SEMI-VOWEL (if any) at the place of 0.
169 (while tail
170 ;; At first, make a copy.
171 (setcar tail (copy-sequence (car tail)))
172 ;; Then, do embedding.
173 (setq place (memq 0 (car tail)))
174 (setcar place (car chars))
175 (setcdr place (cons (nth 1 chars) (cdr place)))
176 (if semi-vowel
177 ;; Embed SEMI-VOWEL in between CHARS.
178 (setcdr place (cons semi-vowel (cdr place))))
179 (setq tail (cdr tail)))
180 patterns))
181
182 ;; Return a string made of characters in CHAR-LIST while composing
183 ;; such characters as vowel-upper, vowel-lower, semi-vowel(lower),
184 ;; and tone-mark with the preceding base character.
185 (defun lrt-compose-string (char-list)
186 ;; Make a copy because the following work alters it.
187 (setq char-list (copy-sequence char-list))
188 (let ((i -1)
189 (l char-list))
190 (while l
191 (if (memq (get-char-code-property (car l) 'phonetic-type)
192 '(vowel-upper vowel-lower semivowel-lower tone))
193 (let (composed-char)
194 (if (< i 0)
195 ;; No preceding base character.
196 (error "Invalid CHAR-LIST: %s" char-list))
197 (setq composed-char
198 (string-to-char (compose-chars (nth i char-list) (car l))))
199 (setcar (nthcdr i char-list) composed-char)
200 (setq l (cdr l))
201 (setcdr (nthcdr i char-list) l))
202 (setq l (cdr l))
203 (setq i (1+ i))))
204 (concat (apply 'vector char-list))))
205
206 (defun lrt-compose-c-s-v (consonant semi-vowel vowel-pattern)
207 (let ((pattern-list
208 (if (integerp consonant)
209 (lrt-composing-pattern-single-c
210 consonant semi-vowel vowel-pattern)
211 (lrt-composing-pattern-double-c
212 consonant semi-vowel vowel-pattern))))
213 (cons (vector (lrt-compose-string (car pattern-list)))
214 (cons t pattern-list))))
215
216 )
217
218 (defun lrt-handle-maa-sakod ()
219 (interactive)
220 (if (or (= (length quail-current-key) 0)
221 (not quail-current-data))
222 (quail-self-insert-command)
223 (if (not (car quail-current-data))
224 (progn
225 (setq quail-current-data nil)
226 (setq unread-command-events
227 (cons last-command-event unread-command-events))
228 (quail-terminate-translation))
229 (if (not (integerp last-command-event))
230 (error "Bogus calling sequence"))
231 (let* ((maa-sakod (cdr (assq last-command-event lrt-maa-sakod-table)))
232 (maa-sakod-pattern (append
233 (or (cdr (assq maa-sakod
234 (nthcdr 3 quail-current-data)))
235 (nth 2 quail-current-data)
236 (nth 1 quail-current-data))
237 (list maa-sakod))))
238 (quail-delete-region)
239 (setq quail-current-str (lrt-compose-string maa-sakod-pattern))
240 (insert quail-current-str)
241 (quail-show-translations)
242 (setq quail-current-data (list nil maa-sakod-pattern))))))
243
244 (defun lrt-handle-tone-mark ()
245 (interactive)
246 (if (= (length quail-current-key) 0)
247 (quail-self-insert-command)
248 (if (not quail-current-data)
249 (progn
250 (setq unread-command-events
251 (cons last-command-event unread-command-events))
252 (quail-terminate-translation))
253 (if (not (integerp last-command-event))
254 (error "Bogus calling sequence"))
255 (let* ((tone-mark (cdr (assoc (char-to-string last-command-event)
256 lrt-tone-mark-table)))
257 (tone-mark-pattern
258 (if (car quail-current-data)
259 (copy-sequence (nth 1 quail-current-data))
260 ;; No need of copy because lrt-handle-maa-sakod should
261 ;; have already done it.
262 (nth 1 quail-current-data)))
263 (tail tone-mark-pattern)
264 (double-consonant-keys lrt-double-consonant-table)
265 (double-consonant-flag nil)
266 place)
267
268 ;; Set DOUBLE-CONSONANT-FLAG to t if a user entered a double
269 ;; consonant.
270 (while (and double-consonant-keys (not double-consonant-flag))
271 (setq double-consonant-flag
272 (eq (string-match (car (car double-consonant-keys))
273 quail-current-key)
274 0)
275 double-consonant-keys (cdr double-consonant-keys)))
276
277 ;; Find a place to embed TONE-MARK. It should be after a
278 ;; single or double consonant and following upper or lower vowels.
279 (while (and tail (not place))
280 (if (and
281 (eq (get-char-code-property (car tail) 'phonetic-type)
282 'consonant)
283 ;; Skip `\e(1K\e(B' if it is the first letter of double consonant.
284 (or (not double-consonant-flag)
285 (/= (car tail) ?\e(1K\e(B)))
286 (progn
287 (setq place tail)
288 (setq tail (cdr tail))
289 (while (and tail
290 (memq (get-char-code-property (car tail)
291 'phonetic-type)
292 '(vowel-upper vowel-lower semivowel-lower)))
293 (setq place tail tail (cdr tail))))
294 (setq tail (cdr tail))))
295 ;; Embed TONE-MARK.
296 (setcdr place (cons tone-mark (cdr place)))
297 (quail-delete-region)
298 (insert (lrt-compose-string tone-mark-pattern))
299 (setq quail-current-data nil)
300 (quail-terminate-translation)))))
301
302 (defmacro lrt-generate-quail-map ()
303 `(quail-install-map
304 ',(let ((map (list nil))
305 (semi-vowel-key (car lrt-semi-vowel-sign-lo))
306 (semi-vowel-char (cdr lrt-semi-vowel-sign-lo))
307 l1 e1 l2 e2 pattern key)
308 ;; Single consonants.
309 (setq l1 lrt-single-consonant-table)
310 (while l1
311 (setq e1 (car l1))
312 (quail-defrule-internal (car e1) (vector (cdr e1)) map)
313 (quail-defrule-internal
314 (concat (car e1) semi-vowel-key)
315 (if (stringp (cdr e1))
316 (compose-string (format "%s%c" (cdr e1) semi-vowel-char))
317 (compose-string (format "%c%c" (cdr e1) semi-vowel-char)))
318 map)
319 (setq l2 lrt-vowel-table)
320 (while l2
321 (setq e2 (car l2))
322 (setq key (concat (car e1) (car e2))
323 pattern (lrt-compose-c-s-v (cdr e1) nil (nthcdr 2 e2)))
324 (quail-defrule-internal key pattern map)
325 (quail-defrule-internal
326 (concat key " ")
327 (vector (concat (aref (car pattern) 0) " ")) map)
328 (setq key (concat (car e1) semi-vowel-key (car e2))
329 pattern (lrt-compose-c-s-v (cdr e1) semi-vowel-char
330 (nthcdr 2 e2)))
331 (quail-defrule-internal key pattern map)
332 (quail-defrule-internal
333 (concat key " ")
334 (vector (concat (aref (car pattern) 0) " ")) map)
335 (setq l2 (cdr l2)))
336 (setq l1 (cdr l1)))
337
338 ;; Double consonants.
339 (setq l1 lrt-double-consonant-table)
340 (while l1
341 (setq e1 (car l1))
342 (quail-defrule-internal (car e1) (vector (cdr e1)) map)
343 (quail-defrule-internal
344 (concat (car e1) semi-vowel-key)
345 (vector (concat (compose-string
346 (format "%c%c" (sref (cdr e1) 0) semi-vowel-char))
347 (substring (cdr e1) (charset-bytes 'lao))))
348 map)
349 (setq l2 lrt-vowel-table)
350 (while l2
351 (setq e2 (car l2))
352 (setq key (concat (car e1) (car e2))
353 pattern (lrt-compose-c-s-v (cdr e1) nil (nthcdr 2 e2)))
354 (quail-defrule-internal key pattern map)
355 (quail-defrule-internal
356 (concat key " ")
357 (vector (concat (aref (car pattern) 0) " ")) map)
358 (setq key (concat (car e1) semi-vowel-key (car e2))
359 pattern (lrt-compose-c-s-v (cdr e1) semi-vowel-char
360 (nthcdr 2 e2)))
361 (quail-defrule-internal key pattern map)
362 (quail-defrule-internal
363 (concat key " ")
364 (vector (concat (aref (car pattern) 0) " ")) map)
365 (setq l2 (cdr l2)))
366 (setq l1 (cdr l1)))
367
368 ;; Vowels.
369 (setq l1 lrt-vowel-table)
370 (while l1
371 (setq e1 (car l1) l1 (cdr l1))
372 (quail-defrule-internal (car e1) (vector (nth 1 e1)) map))
373
374 ;; Tone-marks.
375 (setq l1 lrt-tone-mark-table)
376 (while l1
377 (setq e1 (car l1) l1 (cdr l1))
378 (quail-defrule-internal (car e1) (cdr e1) map))
379
380 map)))
381
382 (quail-define-package
383 "lao-lrt" "Lao" "\e(1E\e(BR" t
384 "Lao input method using LRT (Lao Roman Transcription).
385 `\\' (backslash) + number-key => \e(1p\e(B,\e(1q\e(B,\e(1r\e(B,... LAO DIGIT ZERO, ONE, TWO, ...
386 `\\' (backslash) + `\\' => \e(1f\e(B LAO KO LA (REPETITION)
387 `\\' (backslash) + `$' => \e(1O\e(B LAO ELLIPSIS
388 "
389 '(("k" . lrt-handle-maa-sakod)
390 ("g" . lrt-handle-maa-sakod)
391 ("y" . lrt-handle-maa-sakod)
392 ("d" . lrt-handle-maa-sakod)
393 ("n" . lrt-handle-maa-sakod)
394 ("b" . lrt-handle-maa-sakod)
395 ("m" . lrt-handle-maa-sakod)
396 ("v" . lrt-handle-maa-sakod)
397 ("w" . lrt-handle-maa-sakod)
398 ("'" . lrt-handle-tone-mark)
399 ("\"" . lrt-handle-tone-mark)
400 ("^" . lrt-handle-tone-mark)
401 ("+" . lrt-handle-tone-mark)
402 ("~" . lrt-handle-tone-mark))
403 'forget-last-selection 'deterministic 'kbd-translate 'show-layout
404 nil nil nil nil nil t)
405
406 (lrt-generate-quail-map)
407
408 ;; Additional key definitions for Lao digits.
409
410 (quail-defrule "\\0" ?\e(1p\e(B)
411 (quail-defrule "\\1" ?\e(1q\e(B)
412 (quail-defrule "\\2" ?\e(1r\e(B)
413 (quail-defrule "\\3" ?\e(1s\e(B)
414 (quail-defrule "\\4" ?\e(1t\e(B)
415 (quail-defrule "\\5" ?\e(1u\e(B)
416 (quail-defrule "\\6" ?\e(1v\e(B)
417 (quail-defrule "\\7" ?\e(1w\e(B)
418 (quail-defrule "\\8" ?\e(1x\e(B)
419 (quail-defrule "\\9" ?\e(1y\e(B)
420 (quail-defrule "\\\\" ?\e(1f\e(B)
421 (quail-defrule "\\$" ?\e(1O\e(B)
422
423 ;;; quail/lrt.el ends here