菜鸟的 smart-input-source.el 先上一个预览版 :-)
;;; imbot.el --- an input method management bot: automatic system input method switch -*- lexical-binding: t; -*-
(require 'subr-x)
;; Input source specific cursor color
(defvar imbot--im-inactive-cursor-color "white")
(defvar imbot--im-active-cursor-color "green")
(defface imbot--inline-face '()
"inline overlay."
:group 'imbot)
(set-face-attribute
'imbot--inline-face nil
:foreground (face-attribute 'font-lock-constant-face :foreground)
:inverse-video t)
(defvar imbot-command "fcitx-remote")
(defvar imbot--im-active nil "buffer local input method state")
;; (message "im %s" imbot--im-active)
(make-variable-buffer-local 'imbot--im-active)
(defun imbot--im-active-p ()
(let ((output
(let (deactivate-mark)
(with-temp-buffer
(call-process imbot-command nil t)
(buffer-string)))))
(char-equal
(aref output 0) ?2)))
(defun imbot--save-state ()
(setq imbot--im-active (imbot--im-active-p)))
(defun imbot--activate-im ()
(call-process imbot-command nil nil nil "-o"))
(defun imbot--deactivate-im ()
(imbot--save-state)
(call-process imbot-command nil nil nil "-c"))
(defun imbot--maybe-activate-im ()
(if imbot--im-active
(imbot--activate-im)
(imbot--deactivate-im)))
(defvar imbot--prefix-override-keys
'("C-c" "C-x" "C-h"))
(defvar imbot--prefix-override-map-alist nil)
(let ((keymap (make-sparse-keymap)))
(dolist (prefix
imbot--prefix-override-keys)
(define-key keymap (kbd prefix)
#'imbot--prefix-override-handler))
(setq imbot--prefix-override-map-alist
`((imbot--prefix-override . ,keymap))))
(defvar imbot--prefix-override nil "imbot prefix override state")
(defvar imbot--last-buffer nil)
(defun imbot--prefix-override-handler (arg)
"Prefix key handler with ARG."
(interactive "P")
(let* ((keys (this-command-keys)))
;; temporarily disable prefix override
(setq imbot--prefix-override nil)
(imbot--deactivate-im)
;; Restore the prefix arg
(setq prefix-arg arg)
(prefix-command-preserve-state)
;; (message "1 this command %s" this-command)
(setq this-command nil)
;; Push the key back on the event queue
(setq unread-command-events
(append (mapcar (lambda (e) `(t . ,e)) (listify-key-sequence keys))
unread-command-events))))
(defun imbot--pre-command-switcher ()
(setq imbot--last-buffer (current-buffer)))
(defun imbot--post-command-switcher ()
;; (message "2 this command %s" this-command)
(cond
;; restore im state after prefix sequence completed
((and (not imbot--prefix-override) this-command)
(setq imbot--prefix-override t)
(imbot--maybe-activate-im))
;; save im state on buffer switch and restore im state
((not (eq imbot--last-buffer (current-buffer)))
(when (buffer-live-p imbot--last-buffer)
(with-current-buffer imbot--last-buffer
(imbot--save-state)))
(imbot--maybe-activate-im))
(t nil)))
(defun imbot--prefix-override-enable (&optional args)
(add-to-list 'emulation-mode-map-alists 'imbot--prefix-override-map-alist))
(defun imbot--prefix-override-disable (&optional args)
(setq emulation-mode-map-alists
(delq 'imbot--prefix-override-map-alist
emulation-mode-map-alists)))
(defvar imbot--prefix-reinstate-triggers
'(evil-local-mode yas-minor-mode eaf-mode)
"modes mess with `emulation-mode-map-alists")
(defun imbot-mode-enable ()
(when (and (boundp 'evil-mode) evil-mode)
(add-hook 'evil-insert-state-exit-hook #'imbot--deactivate-im)
(add-hook 'evil-emacs-state-exit-hook #'imbot--deactivate-im)
(add-hook 'evil-insert-state-entry-hook #'imbot--maybe-activate-im)
(add-hook 'evil-emacs-state-entry-hook #'imbot--maybe-activate-im))
(add-hook 'pre-command-hook #'imbot--pre-command-switcher)
(add-hook 'post-command-hook #'imbot--post-command-switcher)
(add-hook 'focus-out-hook #'imbot--save-state)
(add-hook 'focus-in-hook #'imbot--maybe-activate-im)
(add-hook 'minibuffer-setup-hook #'imbot--deactivate-im)
(imbot--prefix-override-enable)
(setq imbot--prefix-override t)
(dolist (trigger imbot--prefix-reinstate-triggers)
(advice-add trigger :after #'imbot--prefix-override-enable)))
(defun imbot-mode-disable ()
(imbot--deactivate-im)
(when (and (boundp 'evil-mode) evil-mode)
(remove-hook 'evil-insert-state-exit-hook #'imbot--deactivate-im)
(remove-hook 'evil-emacs-state-exit-hook #'imbot--deactivate-im)
(remove-hook 'evil-insert-state-entry-hook #'imbot--maybe-activate-im)
(remove-hook 'evil-emacs-state-entry-hook #'imbot--maybe-activate-im))
(remove-hook 'pre-command-hook #'imbot--pre-command-switcher)
(remove-hook 'post-command-hook #'imbot--post-command-switcher)
(remove-hook 'focus-out-hook #'imbot--save-state)
(remove-hook 'focus-in-hook #'imbot--maybe-activate-im)
(remove-hook 'minibuffer-setup-hook #'imbot--deactivate-im)
(imbot--prefix-override-disable)
(dolist (trigger imbot--prefix-reinstate-triggers)
(advice-remove trigger #'imbot--prefix-override-enable)))
(define-minor-mode imbot-mode
"input method manage bot"
:global t
:init-value nil
(if imbot-mode
(imbot-mode-enable)
(imbot-mode-disable)))
(provide 'imbot)
;;; imbot.el ends here
下一步问题:
- 在buffer变化时执行一行代码,保存输入法状态现在是用 pre-command hook和post command hook,但是有可能buffer切换不是因为commandh导致的
- 操作系统切换输入法快捷键绑定到一个脚本,当前窗口是emacs,执行切换时用 emacsclient改变输入法状态变量
- 加入 inline mode