18673
|
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" . ?(1!(B)
|
|
40 ("kh" . ?(1"(B)
|
|
41 ("qh" . ?(1$(B)
|
|
42 ("ng" . ?(1'(B)
|
|
43 ("j" . ?(1((B)
|
|
44 ("s" . ?(1J(B)
|
|
45 ("x" . ?(1*(B)
|
|
46 ("y" . ?(1-(B)
|
|
47 ("d" . ?(14(B)
|
|
48 ("t" . ?(15(B)
|
|
49 ("th" . ?(16(B)
|
|
50 ("dh" . ?(17(B)
|
|
51 ("n" . ?(19(B)
|
|
52 ("b" . ?(1:(B)
|
|
53 ("p" . ?(1;(B)
|
|
54 ("hp" . ?(1<(B)
|
|
55 ("fh" . ?(1=(B)
|
|
56 ("ph" . ?(1>(B)
|
|
57 ("f" . ?(1?(B)
|
|
58 ("m" . ?(1A(B)
|
|
59 ("gn" . ?(1B(B)
|
|
60 ("l" . ?(1E(B)
|
|
61 ("r" . ?(1C(B)
|
|
62 ("v" . ?(1G(B)
|
|
63 ("w" . ?(1G(B)
|
|
64 ("hh" . ?(1K(B)
|
|
65 ("O" . ?(1M(B)
|
|
66 ("h" . ?(1N(B)
|
|
67 ("nh" . ?(1|(B)
|
|
68 ("mh" . ?(1}(B)
|
|
69 ("lh" . ?0(1K\1(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" . "(1K'(B")
|
|
77 ("yh" . "(1K](B")
|
|
78 ("wh" . "(1KG(B")
|
|
79 ("hl" . "(1KE(B")
|
|
80 ("hy" . "(1K-(B")
|
|
81 ("hn" . "(1K9(B")
|
|
82 ("hm" . "(1KA(B")
|
|
83 ))
|
|
84
|
|
85 (defconst lrt-semi-vowel-sign-lo
|
|
86 '("r" . ?(1\(B))
|
|
87
|
|
88 (defconst lrt-vowel-table
|
|
89 '(("a" "(1P(B" (0 ?(1P(B) (0 ?(1Q(B))
|
|
90 ("ar" "(1R(B" (0 ?(1R(B))
|
|
91 ("i" "(1T(B" (0 ?(1T(B))
|
|
92 ("ii" "(1U(B" (0 ?(1U(B))
|
|
93 ("eu" "(1V(B" (0 ?(1V(B))
|
|
94 ("ur" "(1W(B" (0 ?(1W(B))
|
|
95 ("u" "(1X(B" (0 ?(1X(B))
|
|
96 ("uu" "(1Y(B" (0 ?(1Y(B))
|
|
97 ("e" "(1`(B (1P(B" (?(1`(B 0 ?(1P(B) (?(1`(B 0 ?(1Q(B))
|
|
98 ("ee" "(1`(B" (?(1`(B 0))
|
|
99 ("ae" "(1a(B (1P(B" (?(1a(B 0 ?(1P(B) (?(1a(B 0 ?(1Q(B))
|
|
100 ("aa" "(1a(B" (?(1a(B 0))
|
|
101 ("o" "(1b(B (1P(B" (?(1b(B 0 ?(1P(B) (0 ?(1[(B) (?(1-(B ?(1b(B 0 ?(1Q(B) (?(1G(B ?(1b(B 0 ?(1Q(B))
|
|
102 ("oo" "(1b(B" (?(1b(B 0))
|
|
103 ("oe" "(1`(B (1RP(B" (?(1`(B 0 ?(1R(B ?(1P(B) (0 ?(1Q(B ?(1M(B))
|
|
104 ("or" "(1m(B" (0 ?(1m(B) (0 ?(1M(B))
|
|
105 ("er" "(1`(B (1T(B" (?(1`(B 0 ?(1T(B))
|
|
106 ("ir" "(1`(B (1U(B" (?(1`(B 0 ?(1U(B))
|
|
107 ("oua" "(1[GP(B" (0 ?(1[(B ?(1G(B ?(1P(B) (0 ?(1Q(B ?(1G(B))
|
|
108 ("ua" "(1[G(B" (0 ?(1[(B ?(1G(B) (0 ?(1G(B))
|
|
109 ("ie" "(1`Q]P(B" (?(1`(B 0 ?(1Q(B ?(1](B ?(1P(B) (0 ?(1Q(B ?(1](B))
|
|
110 ("ia" "(1`Q](B" (?(1`(B 0 ?(1Q(B ?(1](B) (0 ?(1](B))
|
|
111 ("eua" "(1`VM(B" (?(1`(B 0 ?(1V(B ?(1M(B))
|
|
112 ("ea" "(1`WM(B" (?(1`(B 0 ?(1W(B ?(1M(B))
|
|
113 ("ai" "(1d(B" (?(1d(B 0))
|
|
114 ("ei" "(1c(B" (?(1c(B 0))
|
|
115 ("ow" "(1`[R(B" (?(1`(B 0 ?(1[(B ?(1R(B))
|
|
116 ("am" "(1S(B" (?(1S(B 0))))
|
|
117
|
|
118 ;; Maa-sakod is put at the tail.
|
|
119 (defconst lrt-maa-sakod-table
|
|
120 '((?k . ?(1!(B)
|
|
121 (?g . ?(1'(B)
|
|
122 (?y . ?(1-(B)
|
|
123 (?d . ?(14(B)
|
|
124 (?n . ?(19(B)
|
|
125 (?b . ?(1:(B)
|
|
126 (?m . ?(1A(B)
|
|
127 (?v . ?(1G(B)
|
|
128 (?w . ?(1G(B)
|
|
129 ))
|
|
130
|
|
131 (defconst lrt-tone-mark-table
|
|
132 '(("'" . ?(1h(B)
|
|
133 ("\"" . ?(1i(B)
|
|
134 ("^" . ?(1j(B)
|
|
135 ("+" . ?(1k(B)
|
|
136 ("~" . ?(1l(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 str))
|
|
164 place)
|
|
165 ;; Embed C and SEMI-VOWEL (if any) at the place of 0.
|
|
166 (while tail
|
|
167 ;; At first, make a copy.
|
|
168 (setcar tail (copy-sequence (car tail)))
|
|
169 ;; Then, do embedding.
|
|
170 (setq place (memq 0 (car tail)))
|
|
171 (setcar place (car chars))
|
|
172 (setcdr place (cons (nth 1 chars) (cdr place)))
|
|
173 (if semi-vowel
|
|
174 ;; Embed SEMI-VOWEL in between CHARS.
|
|
175 (setcdr place (cons semi-vowel (cdr place))))
|
|
176 (setq tail (cdr tail)))
|
|
177 patterns))
|
|
178
|
|
179 ;; Return a string made of characters in CHAR-LIST while composing
|
|
180 ;; such characters as vowel-upper, vowel-lower, semi-vowel(lower),
|
|
181 ;; and tone-mark with the preceding base character.
|
|
182 (defun lrt-compose-string (char-list)
|
|
183 ;; Make a copy because the following work alters it.
|
|
184 (setq char-list (copy-sequence char-list))
|
|
185 (let ((i -1)
|
|
186 (l char-list))
|
|
187 (while l
|
|
188 (if (memq (get-char-code-property (car l) 'phonetic-type)
|
|
189 '(vowel-upper vowel-lower semivowel-lower tone))
|
|
190 (let (composed-char)
|
|
191 (if (< i 0)
|
|
192 ;; No preceding base character.
|
|
193 (error "Invalid CHAR-LIST: %s" char-list))
|
|
194 (setq composed-char
|
|
195 (string-to-char (compose-chars (nth i char-list) (car l))))
|
|
196 (setcar (nthcdr i char-list) composed-char)
|
|
197 (setq l (cdr l))
|
|
198 (setcdr (nthcdr i char-list) l))
|
|
199 (setq l (cdr l))
|
|
200 (setq i (1+ i))))
|
|
201 (concat (apply 'vector char-list))))
|
|
202
|
|
203 (defun lrt-compose-c-s-v (consonant semi-vowel vowel-pattern)
|
|
204 (let ((pattern-list
|
|
205 (if (integerp consonant)
|
|
206 (lrt-composing-pattern-single-c
|
|
207 consonant semi-vowel vowel-pattern)
|
|
208 (lrt-composing-pattern-double-c
|
|
209 consonant semi-vowel vowel-pattern))))
|
|
210 (cons (vector (lrt-compose-string (car pattern-list)))
|
|
211 (cons t pattern-list))))
|
|
212
|
|
213 )
|
|
214
|
|
215 (defun lrt-handle-maa-sakod ()
|
|
216 (interactive)
|
|
217 (if (= (length quail-current-key) 0)
|
|
218 (quail-self-insert-command)
|
|
219 (if (not (and quail-current-data (car quail-current-data)))
|
|
220 (progn
|
|
221 (setq quail-current-data nil)
|
|
222 (setq unread-command-events
|
|
223 (cons last-command-event unread-command-events))
|
|
224 (quail-terminate-translation))
|
|
225 (if (not (integerp last-command-event))
|
|
226 (error "Bogus calling sequence"))
|
|
227 (let* ((maa-sakod (cdr (assq last-command-event lrt-maa-sakod-table)))
|
|
228 (maa-sakod-pattern (append
|
|
229 (or (cdr (assq maa-sakod
|
|
230 (nthcdr 3 quail-current-data)))
|
|
231 (nth 2 quail-current-data)
|
|
232 (nth 1 quail-current-data))
|
|
233 (list maa-sakod))))
|
|
234 (quail-delete-region)
|
|
235 (setq quail-current-str (lrt-compose-string maa-sakod-pattern))
|
|
236 (insert quail-current-str)
|
|
237 (setq quail-current-key " ")
|
|
238 (quail-show-translations)
|
|
239 (setq quail-current-data (list nil maa-sakod-pattern))))))
|
|
240
|
|
241 (defun lrt-handle-tone-mark ()
|
|
242 (interactive)
|
|
243 (if (= (length quail-current-key) 0)
|
|
244 (quail-self-insert-command)
|
|
245 (if (not quail-current-data)
|
|
246 (progn
|
|
247 (setq unread-command-events
|
|
248 (cons last-command-event unread-command-events))
|
|
249 (quail-terminate-translation))
|
|
250 (if (not (integerp last-command-event))
|
|
251 (error "Bogus calling sequence"))
|
|
252 (let* ((tone-mark (cdr (assoc (char-to-string last-command-event)
|
|
253 lrt-tone-mark-table)))
|
|
254 (tone-mark-pattern
|
|
255 (if (car quail-current-data)
|
|
256 (copy-sequence (nth 1 quail-current-data))
|
|
257 ;; No need of copy because lrt-handle-maa-sakod should
|
|
258 ;; have already done it.
|
|
259 (nth 1 quail-current-data)))
|
|
260 (tail tone-mark-pattern)
|
|
261 place)
|
|
262 ;; Find a place to embed TONE-MARK. It should be after a
|
|
263 ;; single or double consonant.
|
|
264 (while (and tail (not place))
|
|
265 (if (and
|
|
266 ;; Skip `(1K(B', the first letter of double consonant.
|
|
267 (/= (car tail) ?(1K(B)
|
|
268 (eq (get-char-code-property (car tail) 'phonetic-type)
|
|
269 'consonant))
|
|
270 (progn
|
|
271 (setq place tail)
|
|
272 (setq tail (cdr tail))
|
|
273 (while (and tail
|
|
274 (memq (get-char-code-property (car tail)
|
|
275 'phonetic-type)
|
|
276 '(vowel-upper vowel-lower semivowel-lower)))
|
|
277 (setq place tail tail (cdr tail))))
|
|
278 (setq tail (cdr tail))))
|
|
279 ;; Embed TONE-MARK.
|
|
280 (setcdr place (cons tone-mark (cdr place)))
|
|
281 (quail-delete-region)
|
|
282 (insert (lrt-compose-string tone-mark-pattern))
|
|
283 (setq quail-current-data nil)
|
|
284 (quail-terminate-translation)))))
|
|
285
|
|
286 (defmacro lrt-generate-quail-map ()
|
|
287 `(quail-install-map
|
|
288 ',(let ((map (list nil))
|
|
289 (semi-vowel-key (car lrt-semi-vowel-sign-lo))
|
|
290 (semi-vowel-char (cdr lrt-semi-vowel-sign-lo))
|
|
291 l1 e1 l2 e2 pattern key)
|
|
292 ;; Single consonants.
|
|
293 (setq l1 lrt-single-consonant-table)
|
|
294 (while l1
|
|
295 (setq e1 (car l1))
|
|
296 (quail-defrule-internal (car e1) (cdr e1) map)
|
|
297 (quail-defrule-internal
|
|
298 (concat (car e1) semi-vowel-key)
|
|
299 (compose-string (format "%c%c" (cdr e1) semi-vowel-char))
|
|
300 map)
|
|
301 (setq l2 lrt-vowel-table)
|
|
302 (while l2
|
|
303 (setq e2 (car l2))
|
|
304 (setq key (concat (car e1) (car e2))
|
|
305 pattern (lrt-compose-c-s-v (cdr e1) nil (nthcdr 2 e2)))
|
|
306 (quail-defrule-internal key pattern map)
|
|
307 (quail-defrule-internal
|
|
308 (concat key " ")
|
|
309 (vector (concat (aref (car pattern) 0) " ")) map)
|
|
310 (setq key (concat (car e1) semi-vowel-key (car e2))
|
|
311 pattern (lrt-compose-c-s-v (cdr e1) semi-vowel-char
|
|
312 (nthcdr 2 e2)))
|
|
313 (quail-defrule-internal key pattern map)
|
|
314 (quail-defrule-internal
|
|
315 (concat key " ")
|
|
316 (vector (concat (aref (car pattern) 0) " ")) map)
|
|
317 (setq l2 (cdr l2)))
|
|
318 (setq l1 (cdr l1)))
|
|
319
|
|
320 ;; Double consonants.
|
|
321 (setq l1 lrt-double-consonant-table)
|
|
322 (while l1
|
|
323 (setq e1 (car l1))
|
|
324 (quail-defrule-internal (car e1) (vector (cdr e1)) map)
|
|
325 (quail-defrule-internal
|
|
326 (concat (car e1) semi-vowel-key)
|
|
327 (vector (concat (compose-string
|
|
328 (format "%c%c" (sref (cdr e1) 0) semi-vowel-char))
|
|
329 (substring (cdr e1) (charset-bytes 'lao))))
|
|
330 map)
|
|
331 (setq l2 lrt-vowel-table)
|
|
332 (while l2
|
|
333 (setq e2 (car l2))
|
|
334 (setq key (concat (car e1) (car e2))
|
|
335 pattern (lrt-compose-c-s-v (cdr e1) nil (nthcdr 2 e2)))
|
|
336 (quail-defrule-internal key pattern map)
|
|
337 (quail-defrule-internal
|
|
338 (concat key " ")
|
|
339 (vector (concat (aref (car pattern) 0) " ")) map)
|
|
340 (setq key (concat (car e1) semi-vowel-key (car e2))
|
|
341 pattern (lrt-compose-c-s-v (cdr e1) semi-vowel-char
|
|
342 (nthcdr 2 e2)))
|
|
343 (quail-defrule-internal key pattern map)
|
|
344 (quail-defrule-internal
|
|
345 (concat key " ")
|
|
346 (vector (concat (aref (car pattern) 0) " ")) map)
|
|
347 (setq l2 (cdr l2)))
|
|
348 (setq l1 (cdr l1)))
|
|
349
|
|
350 ;; Vowels.
|
|
351 (setq l1 lrt-vowel-table)
|
|
352 (while l1
|
|
353 (setq e1 (car l1) l1 (cdr l1))
|
|
354 (quail-defrule-internal (car e1) (vector (nth 1 e1)) map))
|
|
355
|
|
356 ;; Tone-marks.
|
|
357 (setq l1 lrt-tone-mark-table)
|
|
358 (while l1
|
|
359 (setq e1 (car l1) l1 (cdr l1))
|
|
360 (quail-defrule-internal (car e1) (cdr e1) map))
|
|
361
|
|
362 map)))
|
|
363
|
|
364 (quail-define-package
|
|
365 "lao-lrt" "Lao" "(1"(BR" t
|
|
366 "Lao input method using LRT (Lao Roman Transcription)"
|
|
367 '(("k" . lrt-handle-maa-sakod)
|
|
368 ("g" . lrt-handle-maa-sakod)
|
|
369 ("y" . lrt-handle-maa-sakod)
|
|
370 ("d" . lrt-handle-maa-sakod)
|
|
371 ("n" . lrt-handle-maa-sakod)
|
|
372 ("b" . lrt-handle-maa-sakod)
|
|
373 ("m" . lrt-handle-maa-sakod)
|
|
374 ("v" . lrt-handle-maa-sakod)
|
|
375 ("w" . lrt-handle-maa-sakod)
|
|
376 ("'" . lrt-handle-tone-mark)
|
|
377 ("\"" . lrt-handle-tone-mark)
|
|
378 ("^" . lrt-handle-tone-mark)
|
|
379 ("+" . lrt-handle-tone-mark)
|
|
380 ("~" . lrt-handle-tone-mark))
|
|
381 'forget-last-selection 'deterministic 'kbd-translate 'show-layout)
|
|
382
|
|
383 (lrt-generate-quail-map)
|