]> code.delx.au - gnu-emacs/blob - lisp/international/encoded-kb.el
Revision: miles@gnu.org--gnu-2004/emacs--unicode--0--patch-26
[gnu-emacs] / lisp / international / encoded-kb.el
1 ;;; encoded-kb.el --- handler to input multibyte characters encoded somehow
2
3 ;; Copyright (C) 1995 Electrotechnical Laboratory, JAPAN.
4 ;; Licensed to the Free Software Foundation.
5 ;; Copyright (C) 2002 Free Software Foundation, Inc.
6 ;; Copyright (C) 2003
7 ;; National Institute of Advanced Industrial Science and Technology (AIST)
8 ;; Registration Number H13PRO009
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Commentary:
28
29 ;;; Code:
30
31 (defconst encoded-kbd-mode-map (make-sparse-keymap)
32 "Keymap for Encoded-kbd minor mode.")
33
34 ;; Subsidiary keymaps for handling ISO2022 escape sequences.
35
36 (defvar encoded-kbd-iso2022-esc-map
37 (let ((map (make-sparse-keymap)))
38 (define-key map "$" 'encoded-kbd-iso2022-esc-dollar-prefix)
39 (define-key map "(" 'encoded-kbd-iso2022-designation-prefix)
40 (define-key map ")" 'encoded-kbd-iso2022-designation-prefix)
41 (define-key map "," 'encoded-kbd-iso2022-designation-prefix)
42 (define-key map "-" 'encoded-kbd-iso2022-designation-prefix)
43 map)
44 "Keymap for handling ESC code in Encoded-kbd mode.")
45 (fset 'encoded-kbd-iso2022-esc-prefix encoded-kbd-iso2022-esc-map)
46
47 (defvar encoded-kbd-iso2022-esc-dollar-map
48 (let ((map (make-sparse-keymap)))
49 (define-key map "(" 'encoded-kbd-iso2022-designation-prefix)
50 (define-key map ")" 'encoded-kbd-iso2022-designation-prefix)
51 (define-key map "," 'encoded-kbd-iso2022-designation-prefix)
52 (define-key map "-" 'encoded-kbd-iso2022-designation-prefix)
53 (define-key map "@" 'encoded-kbd-iso2022-designation)
54 (define-key map "A" 'encoded-kbd-iso2022-designation)
55 (define-key map "B" 'encoded-kbd-iso2022-designation)
56 map)
57 "Keymap for handling ESC $ sequence in Encoded-kbd mode.")
58 (fset 'encoded-kbd-iso2022-esc-dollar-prefix
59 encoded-kbd-iso2022-esc-dollar-map)
60
61 (defvar encoded-kbd-iso2022-designation-map
62 (let ((map (make-sparse-keymap))
63 (l charset-list)
64 final-char)
65 (while l
66 (setq final-char (charset-iso-final-char (car l)))
67 (if (> final-char 0)
68 (define-key map (char-to-string final-char)
69 'encoded-kbd-iso2022-designation))
70 (setq l (cdr l)))
71 map)
72 "Keymap for handling ISO2022 designation sequence in Encoded-kbd mode.")
73 (fset 'encoded-kbd-iso2022-designation-prefix
74 encoded-kbd-iso2022-designation-map)
75
76 (defvar encoded-kbd-iso2022-non-ascii-map
77 (let ((map (make-keymap))
78 (i 32))
79 (while (< i 128)
80 (define-key map (char-to-string i) 'encoded-kbd-self-insert-iso2022-7bit)
81 (setq i (1+ i)))
82 (define-key map "\e" 'encoded-kbd-iso2022-esc-prefix)
83 (setq i 160)
84 (while (< i 256)
85 (define-key map (vector i) 'encoded-kbd-handle-8bit)
86 (setq i (1+ i)))
87 map)
88 "Keymap for handling non-ASCII character set in Encoded-kbd mode.")
89
90 ;; One of the symbols `sjis', `iso2022-7', `iso2022-8', `big5', or
91 ;; `utf-8' to denote what kind of coding-system we are now handling in
92 ;; Encoded-kbd mode.
93 (defvar encoded-kbd-coding nil)
94
95 ;; Keep information of designation state of ISO2022 encoding. When
96 ;; Encoded-kbd mode is on, this is set to a vector of length 4, the
97 ;; elements are character sets currently designated to graphic
98 ;; registers 0 thru 3.
99
100 (defvar encoded-kbd-iso2022-designations nil)
101 (put 'encoded-kbd-iso2022-designations 'permanent-local t)
102
103 ;; Keep information of invocation state of ISO2022 encoding. When
104 ;; Encoded-kbd mode is on, this is set to a vector of length 3,
105 ;; graphic register numbers currently invoked to graphic plane 1 and
106 ;; 2, and a single shifted graphic register number.
107
108 (defvar encoded-kbd-iso2022-invocations nil)
109 (put 'encoded-kbd-iso2022-invocations 'permanent-local t)
110
111 (defun encoded-kbd-iso2022-designation ()
112 "Do ISO2022 designation according to the current key in Encoded-kbd mode.
113 The following key sequence may cause multilingual text insertion."
114 (interactive)
115 (let ((key-seq (this-command-keys))
116 (prev-g0-charset (aref encoded-kbd-iso2022-designations
117 (aref encoded-kbd-iso2022-invocations 0)))
118 intermediate-char final-char
119 reg dimension chars charset)
120 (if (= (length key-seq) 4)
121 ;; ESC $ <intermediate-char> <final-char>
122 (setq intermediate-char (aref key-seq 2)
123 dimension 2
124 chars (if (< intermediate-char ?,) 94 96)
125 final-char (aref key-seq 3)
126 reg (mod intermediate-char 4))
127 (if (= (aref key-seq 1) ?$)
128 ;; ESC $ <final-char>
129 (setq dimension 2
130 chars 94
131 final-char (aref key-seq 2)
132 reg 0)
133 ;; ESC <intermediate-char> <final-char>
134 (setq intermediate-char (aref key-seq 1)
135 dimension 1
136 chars (if (< intermediate-char ?,) 94 96)
137 final-char (aref key-seq 2)
138 reg (mod intermediate-char 4))))
139 (if (setq charset (iso-charset dimension chars final-char))
140 (aset encoded-kbd-iso2022-designations reg charset)
141 (error "Character set of DIMENSION %s, CHARS %s, FINAL-CHAR `%c' is not supported"
142 dimension chars final-char))
143
144 (if (memq (aref encoded-kbd-iso2022-designations
145 (aref encoded-kbd-iso2022-invocations 0))
146 '(ascii latin-jisx0201))
147 ;; Graphic plane 0 (0x20..0x7f) is for ASCII. We don't have
148 ;; to handle characters in this range specially.
149 (if (not (memq prev-g0-charset '(ascii latin-jisx0201)))
150 ;; We must exit recursive edit now.
151 (throw 'exit nil))
152 ;; Graphic plane 0 is for non-ASCII.
153 (if (memq prev-g0-charset '(ascii latin-jisx0201))
154 ;; We must handle keys specially.
155 (let ((overriding-local-map encoded-kbd-iso2022-non-ascii-map))
156 (recursive-edit))))))
157
158 (defun encoded-kbd-handle-8bit ()
159 "Handle an 8-bit character entered in Encoded-kbd mode."
160 (interactive)
161 (cond ((eq encoded-kbd-coding 'iso2022-7)
162 (error "Can't handle the character code %d" last-command-char))
163
164 ((eq encoded-kbd-coding 'iso2022-8)
165 (cond ((= last-command-char ?\216)
166 (aset encoded-kbd-iso2022-invocations 2 2))
167
168 ((= last-command-char ?\217)
169 (aset encoded-kbd-iso2022-invocations 2 3))
170
171 ((>= last-command-char ?\240)
172 (encoded-kbd-self-insert-iso2022-8bit 1))
173
174 (t
175 (error "Can't handle the character code %d"
176 last-command-char))))
177
178 ((eq encoded-kbd-coding 'sjis)
179 (encoded-kbd-self-insert-sjis))
180
181 (t
182 (encoded-kbd-self-insert-big5))))
183
184 (defun encoded-kbd-self-insert-iso2022-7bit ()
185 (interactive)
186 (let* ((charset (aref encoded-kbd-iso2022-designations
187 (or (aref encoded-kbd-iso2022-invocations 2)
188 (aref encoded-kbd-iso2022-invocations 0))))
189 (char (if (= (charset-dimension charset) 1)
190 (make-char charset last-command-char)
191 (make-char charset last-command-char (read-char-exclusive)))))
192 (aset encoded-kbd-iso2022-invocations 2 nil)
193 (setq unread-command-events (cons char unread-command-events))))
194
195 (defun encoded-kbd-self-insert-iso2022-8bit (arg)
196 (interactive "p")
197 (cond
198 ((= last-command-char ?\216) ; SS2 (Single Shift 2)
199 (aset encoded-kbd-iso2022-invocations 2 2))
200 ((= last-command-char ?\217) ; SS3 (Single Shift 3)
201 (aset encoded-kbd-iso2022-invocations 2 3))
202 (t
203 (let* ((charset (aref encoded-kbd-iso2022-designations
204 (or (aref encoded-kbd-iso2022-invocations 2)
205 (aref encoded-kbd-iso2022-invocations 1))))
206 (char (if (= (charset-dimension charset) 1)
207 (make-char charset last-command-char)
208 (make-char charset last-command-char
209 (read-char-exclusive)))))
210 (aset encoded-kbd-iso2022-invocations 2 nil)
211 ;; As simply setting unread-command-events may result in
212 ;; infinite-loop for characters 160..255, this is a temporary
213 ;; workaround until we found a better solution.
214 (let ((last-command-char char))
215 (self-insert-command arg))))))
216
217 (defun encoded-kbd-self-insert-sjis ()
218 (interactive)
219 (let ((char (if (or (< last-command-char ?\xA0) (>= last-command-char ?\xE0))
220 (decode-sjis-char (+ (ash last-command-char 8)
221 (read-char-exclusive)))
222 (make-char 'katakana-jisx0201 last-command-char))))
223 (setq unread-command-events (cons char unread-command-events))))
224
225 (defun encoded-kbd-self-insert-big5 ()
226 (interactive)
227 (let ((char (decode-big5-char (+ (ash last-command-char 8)
228 (read-char-exclusive)))))
229 (setq unread-command-events (cons char unread-command-events))))
230
231 (defun encoded-kbd-self-insert-ccl ()
232 (interactive)
233 (let ((str (char-to-string last-command-char))
234 (ccl (coding-system-get (keyboard-coding-system) :ccl-decoder))
235 (vec [nil nil nil nil nil nil nil nil nil])
236 result)
237 (while (= (length (setq result (ccl-execute-on-string ccl vec str t))) 0)
238 (dotimes (i 9) (aset vec i nil))
239 (setq str (format "%s%c" str (read-char-exclusive))))
240 (setq unread-command-events
241 (append result unread-command-events))))
242
243 (defun encoded-kbd-self-insert-charset (arg)
244 (interactive "p")
245 (let* ((charset-list
246 (coding-system-get (keyboard-coding-system) :charset-list))
247 (charset (car charset-list))
248 ;; For the moment, we can assume that the length of CHARSET-LIST
249 ;; is 1, and the dimension of CHARSET is 1.
250 (c (decode-char charset last-command-char)))
251 (unless c
252 (error "Can't decode the code point %d by %s"
253 last-command-char charset))
254 ;; As simply setting unread-command-events may result in
255 ;; infinite-loop for characters 160..255, this is a temporary
256 ;; workaround until we found a better solution.
257 (let ((last-command-char c))
258 (self-insert-command arg))))
259
260 (defun encoded-kbd-self-insert-utf-8 (arg)
261 (interactive "p")
262 (let (len ch)
263 (cond ((< last-command-char #xE0)
264 (setq len 1 ch (logand last-command-char #x1F)))
265 ((< last-command-char #xF0)
266 (setq len 2 ch (logand last-command-char #x0F)))
267 ((< last-command-char #xF8)
268 (setq len 3 ch (logand last-command-char #x07)))
269 (t
270 (setq len 4 ch 0)))
271 (while (> len 0)
272 (setq ch (logior (lsh ch 6) (logand (read-char-exclusive) #x3F))
273 len (1- len)))
274 (let ((last-command-char ch))
275 (self-insert-command arg))))
276
277 (defun encoded-kbd-setup-keymap (coding)
278 ;; At first, reset the keymap.
279 (setcdr encoded-kbd-mode-map nil)
280 ;; Then setup the keymap according to the keyboard coding system.
281 (cond
282 ((eq encoded-kbd-coding 'charset)
283 (let* ((charset (car (coding-system-get coding :charset-list)))
284 (code-space (get-charset-property charset :code-space))
285 (from (max (aref code-space 0) 128))
286 (to (aref code-space 1)))
287 (while (<= from to)
288 (define-key encoded-kbd-mode-map
289 (vector from) 'encoded-kbd-self-insert-charset)
290 (setq from (1+ from)))))
291
292 ((eq encoded-kbd-coding 'sjis)
293 (let ((i 128))
294 (while (< i 256)
295 (define-key encoded-kbd-mode-map
296 (vector i) 'encoded-kbd-self-insert-sjis)
297 (setq i (1+ i)))))
298
299 ((eq encoded-kbd-coding 'big5)
300 (let ((i 161))
301 (while (< i 255)
302 (define-key encoded-kbd-mode-map
303 (vector i) 'encoded-kbd-self-insert-big5)
304 (setq i (1+ i)))))
305
306 ((eq encoded-kbd-coding 'iso2022-7)
307 (define-key encoded-kbd-mode-map "\e" 'encoded-kbd-iso2022-esc-prefix))
308
309 ((eq encoded-kbd-coding 'iso2022-8)
310 (define-key encoded-kbd-mode-map
311 (vector ?\216) 'encoded-kbd-self-insert-iso2022-8bit)
312 (define-key encoded-kbd-mode-map
313 (vector ?\217) 'encoded-kbd-self-insert-iso2022-8bit)
314 (let ((i 160))
315 (while (< i 256)
316 (define-key encoded-kbd-mode-map
317 (vector i) 'encoded-kbd-self-insert-iso2022-8bit)
318 (setq i (1+ i)))))
319
320 ((eq encoded-kbd-coding 'ccl)
321 (let ((valid-codes (or (coding-system-get coding :valid)
322 '((128 . 255))))
323 elt from to)
324 (while valid-codes
325 (setq elt (car valid-codes) valid-codes (cdr valid-codes))
326 (if (consp elt)
327 (setq from (car elt) to (cdr elt))
328 (setq from (setq to elt)))
329 (while (<= from to)
330 (if (>= from 128)
331 (define-key encoded-kbd-mode-map
332 (vector from) 'encoded-kbd-self-insert-ccl))
333 (setq from (1+ from))))))
334
335 ((eq encoded-kbd-coding 'utf-8)
336 (let ((i #xC0))
337 (while (< i 256)
338 (define-key encoded-kbd-mode-map
339 (vector i) 'encoded-kbd-self-insert-utf-8)
340 (setq i (1+ i)))))
341
342 (t
343 (error "Invalid value in encoded-kbd-coding: %s" encoded-kbd-coding))))
344
345
346 ;; Input mode at the time Encoded-kbd mode is turned on is saved here.
347 (defvar saved-input-mode nil)
348
349 (put 'encoded-kbd-mode 'permanent-local t)
350 ;;;###autoload
351 (define-minor-mode encoded-kbd-mode
352 "Toggle Encoded-kbd minor mode.
353 With arg, turn Encoded-kbd mode on if and only if arg is positive.
354
355 You should not turn this mode on manually, instead use the command
356 \\[set-keyboard-coding-system] which turns on or off this mode
357 automatically.
358
359 In Encoded-kbd mode, a text sent from keyboard is accepted
360 as a multilingual text encoded in a coding system set by
361 \\[set-keyboard-coding-system]."
362 :global t
363 ;; We must at first reset input-mode to the original.
364 (if saved-input-mode (apply 'set-input-mode saved-input-mode))
365 (if encoded-kbd-mode
366 (let ((coding (keyboard-coding-system)))
367 (setq saved-input-mode (current-input-mode))
368 (cond ((null coding)
369 (setq encoded-kbd-mode nil)
370 (error "No coding system for keyboard input is set"))
371
372 ((eq (coding-system-type coding) 'shift-jis)
373 (set-input-mode
374 (nth 0 saved-input-mode) (nth 1 saved-input-mode)
375 'use-8th-bit (nth 3 saved-input-mode))
376 (setq encoded-kbd-coding 'sjis))
377
378 ((eq (coding-system-type coding) 'iso-2022)
379 (if (memq '7-bit (coding-system-get coding :flags))
380 (setq encoded-kbd-coding 'iso2022-7)
381 (set-input-mode
382 (nth 0 saved-input-mode) (nth 1 saved-input-mode)
383 'use-8th-bit (nth 3 saved-input-mode))
384 (setq encoded-kbd-coding 'iso2022-8))
385 (setq encoded-kbd-iso2022-designations
386 (coding-system-get coding :designation))
387 (setq encoded-kbd-iso2022-invocations (make-vector 3 nil))
388 (aset encoded-kbd-iso2022-invocations 0 0)
389 (aset encoded-kbd-iso2022-invocations 1 1))
390
391 ((eq (coding-system-type coding) 'big5)
392 (set-input-mode
393 (nth 0 saved-input-mode) (nth 1 saved-input-mode)
394 'use-8th-bit (nth 3 saved-input-mode))
395 (setq encoded-kbd-coding 'big5))
396
397 ((eq (coding-system-type coding) 'ccl)
398 (set-input-mode
399 (nth 0 saved-input-mode) (nth 1 saved-input-mode)
400 'use-8th-bit (nth 3 saved-input-mode))
401 (setq encoded-kbd-coding 'ccl))
402
403 ((and (eq (coding-system-type coding) 'charset)
404 (let* ((charset-list (coding-system-get coding
405 :charset-list))
406 (charset (car charset-list)))
407 (and (= (length charset-list) 1)
408 (= (charset-dimension charset) 1))))
409 (set-input-mode
410 (nth 0 saved-input-mode) (nth 1 saved-input-mode)
411 'use-8th-bit (nth 3 saved-input-mode))
412 (setq encoded-kbd-coding 'charset))
413
414 ((eq (coding-system-type coding) 'utf-8)
415 (set-input-mode
416 (nth 0 saved-input-mode) (nth 1 saved-input-mode)
417 'use-8th-bit (nth 3 saved-input-mode))
418 (setq encoded-kbd-coding 'utf-8))
419
420 (t
421 (setq encoded-kbd-mode nil)
422 (error "Coding-system `%s' is not supported in Encoded-kbd mode"
423 (keyboard-coding-system))))
424 (encoded-kbd-setup-keymap coding))))
425
426 (provide 'encoded-kb)
427
428 ;;; arch-tag: 76f0f9b3-65e7-45c3-b692-59509a87ad44
429 ;;; encoded-kb.el ends here