2

Update 2020-12-22: I have answered the question. Please see below.


I have fcitx installed on a Linux environment. According the to fcitx-diagnose it is correctly installed.

I am using the us-alt-intl keyboard to access diacritics in other language as a default keyboard. But it imposes extra-typing in standard vim or evil mode. Typically,accessing registers or moving to marks adds an extra space, which on extensive usage is somewhat a burden.

I'd like to switch back to a standard us keyboard when not in insert mode. As it turns out that is a common issue for CJK users.

The Chinese layer and the mozc package relies on fcitx to do that job. First, I have not been able to make them work on my installation.

I have attempted to create a layer to that intent.

Being new to layer creation, I have followed the is my packages.el:

(setq fcitx-packages
          '((fcitx :toggle fcitx-enable-fcitx)
            org))  
    
(defun fcitx/init-fcitx ()
      (use-package fcitx
        :init (fcitx-evil-turn-on)
        :config
        (progn
          (setq fcitx-active-evil-states '(insert emacs hybrid))
          (fcitx-default-setup)
          (fcitx-prefix-keys-add "M-m" "C-M-m")
          (when fcitx-fcitx-use-dbus
            (setq fcitx-use-dbus t)))))

This is probably overkill as adding the fcitx package to the .spacemacs file could perhaps be enough

dotspacemacs-additional-packages '(fcitx
                                      mozc
                                      mozc-im
                                      mozc-popup)

How can I add the keyboards in that code (which is faulty anyway).

1

If your purpose is to input Chinese, you could use https://github.com/tumashu/pyim

A native Emacs input method written in pure Emacs Lisp. I just add a new backend pyim-dregcache to pyim. So it requires much less resource and is still fast enough.

The setup is minimum,

(eval-after-load 'pyim
  '(progn
      (setq pyim-dcache-backend 'pyim-dregcache) ; use memory efficient pyim engine
      ;; common setup for pyim ...
      ))
0

I finally took time to review this by myself. I decided on a solution (provided here) that works reasonably for me but there are many alternatives to tackle that feature. They have obvious trade-offs and I do not claim the solution I settled on in the end is optimal.

Besides, input methods and languages are used in different contexts that requires potentially different solutions.

You may be a native English speaker that needs to write occasionally and in given circumstances in a foreign language.

You may be a native of a foreign language who relies on ANSI English for mostly her professional life but otherwise for anything private writes in her own language.

You may be switching between two languages only. Or you may have to juggle with several languages, themselves having several alphabets or syllabics.

First, to avoid duplication of effort for a potential reader, here is a survey of the situation as of recently.

Input methods, Input sources, keyboard layouts and spac/emacs

'Input method' is the name of the software piece that translates a key stroke into an output on your file system. 'Input source' is the Mac OS name of this functionality. It roughly covers what people understand as 'Keyboad layout'. One of its most conspicuous use is to write the symbols of written version of the different languages in the world.

Input methods and keyboard layouts can be handled at two levels from an spac/emacs user's point of view. Within Emacs or at the OS system level.

Defining my own specific need

I use the evil mode in space/macs. My native language and the languages I use on a regular basis require either:

  • an extension of the strict ANSI character sets
  • or a completely different alphabet or type of characters (e.g. Serbian cyrillic and latin) Using the US international keyboard allows to address several European language needs while retaining most of the kwertiop layout. Some features of vi though (register, jumps) requires keys that in the US international keyboad are used as so called "dead keys", keys which when pressed once do not output a character but modify the next input. The ñ in the spanish word niña est produced for example by type '~' then 'n'. Note that '˜'in command mode in vi is a shorthand for 'capitalize'. So in command mode with a US International keyboard, to capitalise I need to type '˜' then 'SPC'. That is still acceptable. Accessing the current register requires /'"/ that is ' followed by ". This requires now two extra-spaces. Manipulation of surroundings is a particular pain in this model. cs5w"' to change the string bracket from " to ' makes you pause before execution.

If you are in an entirely different keyboard layout for english (dvorak or colemak) or for another language, this is not even a starter.

One solution is to switch back to a standard US English (Qwertyop) layout when in command mode then back to... another keyboard layout in input mode.

How this is can be achieved is the purpose of the rest of this post.

Native emacs solution

Emacs has by itself the capacity to manage input methods natively. That is it has the capability to encode keystrokes and translates them into characters within the application independently of the OS.

M-x list-input-methods

is your friend. Here are references I found related to emacs input methods. https://www.reddit.com/r/spacemacs/comments/8lu5kd/change_keyboard_layout_only_in_insert_mode/

https://clarkgrubb.com/personal-keyboard#latin

https://arenzana.org/2019/01/emacs-locale-management-and-input-methods/

https://charalambosthemistocleous.com/emacs,/writing/2017/12/13/emacs-input.html

Quoting from the last reference:

If you switched the layout using emacs itself, not the system it'll work as you would expect, so the keybinding for it is "C-" it'll show you a helm autocomplete to choose your layout, this layout will be used only in Insert mode, and you can always switch back and forth between the English layout and in my case the Arabic layout using "C-"

This is a perfectly valid approach that I contemplated. I am not spending all my life in spac/emacs (yet). So it makes often sense to have the current input language carried over system-wide.

OS native approach

Emacs will use by default the input method currently active on your OS. Unless you explicitly asked it to switch to a native one, that is.

Another approach is thus to switch from Emacs the OS input method.

This requires two pieces of software:

  1. an external executable as there is currently no direct high level API to the input methods in any of the major OS'.
  2. some e-list code to manipulate the previous.

The coupling between these two pieces of software can vary. They may have been produced by a single author that has ignored the rest of the echo system. In the latest development though several "backends" have been planned as well as functionality to extend to new ones (this is the case of https://github.com/laishulu/emacs-smart-input-source for example).

OS input switcher binaries

It turns out there are score of input switcher provided by the community as open software. They may be available only on a specific OS flavour or may have been compiled on several OS. Here are a few candidates.

  1. fcitx-remote:

    https://github.com/xcodebuild/fcitx-remote-for-osx https://github.com/cute-jumper/fcitx-remote-for-windows

  2. im-select

    https://github.com/daipeihust/im-select

  3. input source switcher

    https://gist.github.com/ghost355/a967417bb7e826e833d4

  4. swim

    https://github.com/mitsuse/swim

  5. macsim Of not EMP (Emacs Mac OS X Port) has its own input switcher embeded.

You will often need to install them on your OS. On Linux, the situation seems slightly better than on Mac OS X and Windows but I have been using a Mac OS X for the past few months and have not tested the machinery on my usual distribution.

e-lisp interfaces

  1. fcitx.el https://github.com/cute-jumper/fcitx.el/blob/master/fcitx.el This package provides a set of functions to make fcitx work better in Emacs. This is originally designed to be used along with `fcitx' on Linux, but it can also be used on other platforms with other input methods. Targeted OS:

    • For OSX users, see [fcitx-remote-for-osx]
    • For Windows users, see [fcitx-remote-for-windows]
    • For users who want to add support for other input methods, see the following section: Work with Other Input methods
  2. im-switch https://gist.github.com/penn201500/fd445603ea05faef4c9f5b2e102613ad with im-select: https://github.com/daipeihust/im-select OS:

    • windows
    • mac
    • Linux ?
  3. sis This one looks very good but I could not make it work: https://github.com/laishulu/emacs-smart-input-source

    Theoretically it works with any underlying input switcher that works as follows:

    • YOUR_ISM:
      • Run =YOUR_ISM= will output the current input source
      • Run =YOUR_ISM INPUT_SOURCE_ID= will select INPUT_SOURCE_ Targeted OS:
    • Mac OS X: with either Emacs Mac Port (EMP) or macsim
    • Windows: im-select par exemple
    • linux: fcitx
  4. EmacsAutoKbdSwitch.el
    old works with issw: https://github.com/vovkasm/input-source-switcher Only for mac os X.

My current solution

I ended up with input-switch.el not entirely as a deliberate choice. I was already fairly engaged into making it work when I stumble upon /sis/, if memory serves me well.

It has been working well for me. I tweak one of the 3 or 4 versions of the script floating on the cloud because I had specific needs. I wanted in particular to be able to switch from within emacs to several keyboard layouts. I mapped these functions in spacemacs to: =o i i= (switch input mode to US international) and =o s= (switch to serbian: latin and cyrillic).

Here is my modified code:

(message "-- im-switch.el --")

;; switch to english input method when switching to normal mode
;; and switch back when entering insert/replace modes
;; need external script support, currently mac-only
;; https://gist.github.com/celadevra/7ae45920e2494fbc38ef
(defvar default-im "com.apple.keylayout.US" "Default ascii-only input method")
(defvar usint-im "com.apple.keylayout.USInternational-PC" "US International input method")
(defvar srlat-im "com.apple.keylayout.Serbian-Latin" "Apple Serbian Latin input method")
(defvar sr-im "com.apple.keylayout.Serbian" "Serbian input method")
(defvar prev-im usint-im "IM that I use when starting Emacs and exiting insert mode")


(defun im-use-english ()
  "Switch to english input method on a Mac. im-select is a tool
provided at https://github.com/daipeihust/im-select"
  (interactive)
  (cond ((eq system-type 'darwin)
         (call-process-shell-command (concat "/usr/local/bin/im-select " default-im)))))

(defun im-use-usint()
  "Switch to Serbian Latin input method on a Mac. im-select is a tool
provided at https://github.com/daipeihust/im-select"
  (interactive)
  (cond ((eq system-type 'darwin)
         (setq prev-im  usint-im))))

(defun im-use-sr()
  "Switch to Serbian Latin input method on a Mac. im-select is a tool
provided at https://github.com/daipeihust/im-select"
  (interactive)
  (cond ((eq system-type 'darwin)
         (setq prev-im  sr-im))))

(defun im-use-srlatin()
  "Switch to Serbian Latin input method on a Mac. im-select is a tool
provided at https://github.com/daipeihust/im-select"
  (interactive)
  (cond ((eq system-type 'darwin)
         (setq prev-im  srlat-im))))

(defun im-remember ()
  "Remember the input method being used in insert mode,so we can switch to it in other modes."
  (interactive)
  (cond ((eq system-type 'darwin)
         (setq prev-im (substring (shell-command-to-string "/usr/local/bin/im-select") 0 -1)))))
;; (defun im--list()
;;   "Remember the input method being used in insert mode,so we can switch to it in other modes."
;;   (interactive)
;;   (cond ((eq system-type 'darwin)
;;          (shell-command-to-string "/usr/local/bin/im-select")))
;;   )
;; (defun im-choose ()
;;   "Remember the input method being used in insert mode,so we can switch to it in other modes."
;;   (interactive)
;;   (cond ((eq system-type 'darwin)
;;          (call-process-shell-command concat)) (substring (shell-command-to-string "/usr/local/bin/im-select") 0 -1)))
(defun im-use-prev ()
  "Use previous input method.
If previous input method is not defined, use default method"
  (interactive)
  (cond ((eq system-type 'darwin)
         (if prev-im
             (call-process-shell-command (concat "/usr/local/bin/im-select " prev-im))
           (call-process-shell-command (concat "/usr/local/bin/im-select " default-im))))))

(add-hook 'evil-normal-state-entry-hook 'im-use-english)
(add-hook 'evil-insert-state-entry-hook 'im-use-prev)
(add-hook 'evil-insert-state-exit-hook 'im-remember)
(add-hook 'evil-replace-state-entry-hook 'im-use-prev)
(add-hook 'evil-replace-state-exit-hook 'im-remember)
(add-hook 'evil-emacs-state-entry-hook 'im-use-english)
(add-hook 'minibuffer-setup-hook 'im-use-prev)
(message "-- im-switch key oii oisc oisl--")
(spacemacs/set-leader-keys "oii" 'im-use-usint)
(spacemacs/set-leader-keys "oisc" 'im-use-sr)
(spacemacs/set-leader-keys "oisl" 'im-use-srlatin)
(provide 'im-switch)
;;;im-switch.el ends here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.