(defgroup double nil
"Remap keyboard, but get original by typing the same key twice."
:group 'i18n)
(defcustom double-map
'((?\ (?\' "\370" "'")
(?\[ "\345" "[")
(?\: "\306" ":")
(?\" "\330" "\"")
(?\{ "\305" "{"))
"Alist of key translations activated by double mode.
Each entry is a list with three elements:
1. The key activating the translation.
2. The string to be inserted when the key is pressed once.
3. The string to be inserted when the key is pressed twice."
:group 'double
:type '(repeat (list (character :tag "Key")
(string :tag "Once")
(string :tag "Twice"))))
(defcustom double-prefix-only t
"*Non-nil means that Double mode mapping only works for prefix keys.
That is, for any key `X' in `double-map', `X' alone will be mapped
but not `C-u X' or `ESC X' since the X is not the prefix key."
:group 'double
:type 'boolean)
(defvar double-last-event nil)
(defun double-read-event (prompt)
(if isearch-mode (isearch-update))
(if prompt
(prog2 (message "%s%c" prompt double-last-event)
(read-event)
(message ""))
(read-event)))
(global-set-key [ignore] '(lambda () (interactive)))
(or (boundp 'isearch-mode-map)
(load-library "isearch"))
(define-key isearch-mode-map [ignore]
(function (lambda () (interactive) (isearch-update))))
(defun double-translate-key (prompt)
(let ((key last-input-char))
(cond (unread-command-events
(vector key))
((and double-prefix-only
(> (length (this-command-keys)) 1))
(vector key))
((eq key 'magic-start)
(let ((new (double-read-event prompt))
(entry (assoc double-last-event double-map)))
(force-window-update (selected-window))
(if (eq new double-last-event)
(progn
(setq unread-command-events
(append (make-list (1- (length (nth 1 entry)))
127)
(nth 2 entry)
'(magic-end)))
(vector 127))
(setq unread-command-events (list new))
[ignore])))
((eq key 'magic-end)
[ignore])
(t
(let ((exp (nth 1 (assoc key double-map))))
(setq double-last-event key)
(setq unread-command-events
(append (substring exp 1) '(magic-start)))
(vector (aref exp 0)))))))
(defun double-setup (enable-flag)
(if enable-flag
(progn
(kill-local-variable 'key-translation-map)
(make-local-variable 'key-translation-map)
(setq key-translation-map (if (keymapp key-translation-map)
(copy-keymap key-translation-map)
(make-sparse-keymap)))
(mapcar (function (lambda (entry)
(define-key key-translation-map
(vector (nth 0 entry))
'double-translate-key)))
(append double-map '((magic-start) (magic-end)))))
(kill-local-variable 'key-translation-map)))
(defcustom double-mode nil
"Toggle Double mode.
Setting this variable directly does not take effect;
use either \\[customize] or the function `double-mode'."
:set (lambda (symbol value)
(double-mode (if value 1 0)))
:initialize 'custom-initialize-default
:link '(emacs-commentary-link "double")
:type 'boolean
:require 'double
:group 'double)
(make-variable-buffer-local 'double-mode)
(or (assq 'double-mode minor-mode-alist)
(setq minor-mode-alist
(cons '(double-mode " Double") minor-mode-alist)))
(defun double-mode (arg)
"Toggle Double mode.
With prefix arg, turn Double mode on iff arg is positive.
When Double mode is on, some keys will insert different strings
when pressed twice. See variable `double-map' for details."
(interactive "P")
(if (or (and (null arg) double-mode)
(<= (prefix-numeric-value arg) 0))
(if double-mode
(progn
(let ((double-map))
(double-setup nil))
(setq double-mode nil)
(force-mode-line-update)))
(if double-mode
()
(double-setup t)
(setq double-mode t)
(force-mode-line-update))))
(provide 'double)