読者です 読者をやめる 読者になる 読者になる

blechmusikの日記

キー・カスタマイズ・ソフトウェア "DvorakJ" の覚え書きをはじめとして様々なことを書いています。

Emacs のウィンドウを揺らすことで、IME の操作を有効にする

概要

 Windows 8 環境下で NTEmacs を使うと、場合によっては日本語入力がうまくいかない。その対処策として判明したのは、 Emacs のウィンドウを移動したりサイズを変更することである。そこでAutoHotkey_L のスクリプトを用いて対処策を実現し、その AutoHotkey_L スクリプトを Emacs lisp 経由で実行することにした。こうすれば問題の症状に対処することができる。

問題のありか

 これまで私は、Windows 8Windows 7 の環境下で、 gnupack (cygwn + emacs package) 所収の Emacs (NTEmacs) を利用してきた。この gnupack は、 Windows ユーザーから関心を集めているツール集であり、今年出版された『Emacs実践入門』*1では、Windows ユーザーにとって導入しやすい、 Emacs (NTEmacs) が収録されているパッケージだと位置づけられている*2。たしかに、Emacs を即座に使ってみたい Windows ユーザーにとって、gnupack は手軽かつ便利なパッケージなのだ。
 先日、ime-enable-document-feed有効時のフリーズ問題解消? - gnupackの開発メモで配布されている Emacs version 24.3 を入手し、 gnupack に収録されている Emacs を最新版へと更新したら、Windows 8 で日本語入力がうまくいかなくなった(Windows 7 においては同様の症状は生じない)。日本語で入力するために Emacs 上で変換キーを押しても IME が有効にならないのである。eamat @Cabinet - IME制御(IME.ahk) を使ってIME の状態を監視している最中に変換キーを押したら、MEの状態には変化が見あたらないという、以下の画像のとおりの結果が出た。本来であれば、変換キーを押せば IME_GET の値は 0 と 1 を交互に切り替えるはずである。しかし、そうはならずに、" is undefiend" や " is undefined" とのエラーメッセージが表示されるだけなのだった。

f:id:blechmusik2:20130708023821p:plain
f:id:blechmusik2:20130708023830p:plain

参考資料として、Meryで同様の動作をしたその結果を画像形式で示そう。IME_GET の値が正しく変化していることに気づくだろう。

f:id:blechmusik2:20130708023849p:plain
f:id:blechmusik2:20130708023858p:plain

 では、どうすればこの問題を解消できるのか。私の場合、Windows キー + space で複数の IME を切り替えることで対処してきた。普段利用している ATOK から Microsoft IME へと IME を切り替え、その状態で何かしら入力し、続けて Microsoft IME から ATOK へと IME を再度切り替えていた。こうすれば日本語入力に支障は無くなるのだが、問題を対処するための手順としては煩雑なものと評価せざるを得まい。
 結論を先取りすると、私が頼った対処策は AutoHotkey と emacs を連動させ、emacs の位置を調整するというものである。

対処策

 私が現在採用している対処策に関しては、 twitter 上のつぶやきから着想を得た。

 この指摘のとおり、「NTEmacsのウインドウを移動させる・サイズ変更す」れば、「半角/全角キーが機能」するようになる。ただし、ここでいうサイズ変更やウィンドウ移動というのは、マウス操作を経由するものであって、AutoHotkey の WinMove - AutoHotkeyJpを使うものではない。後者の場合は、確かにウィンドウを移動させることはできるが、半角/全角キーを機能させることにはつながらないのだ。
 こうして、対処策は次の手順としてまとめられる。

  • マウスの動作によってウィンドウを移動する、Windows 8 向けの AutoHotkey (AutoHotkey_L) スクリプトを作成する(後述のshaking-the-window-of-ntemacs-to-enable-ime)
  • そのスクリプトを emacs lisp で呼び出すようにする(後述のelisp)

 後者の elisp を Emacs 起動時に自動的に読み込むか、手動で評価することによって、件の日本語入力のつまづきが解消される。

AutoHotkey_L のスクリプト (exeバイナリ化すること)

ここでは、AutoHotkey_L の現行スクリプト名は shaking-the-window-of-ntemacs-to-enable-ime.ahk で、exe バイナリ化したファイルの名前は shaking-the-window-of-ntemacs-to-enable-ime.exe とする。

;; -*-mode: ahk; coding:utf-8-with-signature-dos-*-"
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
#SingleInstance force

DetectHiddenWindows, On

whnd := WinExist("ahk_class Emacs")

if (( whnd ) and ("WIN_8" == A_OSVersion)){
    WinActivate, ahk_id %whnd%
    MouseGetPos, mouseX, mouseY

    ;; mouseButton := "left"
    mouseButton := "right"
    if (get_script_parameters()[1]) {
        mouseButton := get_script_parameters()[1]
    }

    BlockInput, MouseMove

    MouseClick, %mouseButton%, 50, 15, , 0, D
    sleep,50
    MouseClick, %mouseButton%, 15, 0, , 0, D, R
    sleep,50
    MouseClick, %mouseButton%, -15, 0, , 0, U, R
    sleep,50
    MouseMove, %mouseX%, %mouseY%, 0

    BlockInput, MouseMoveOff

    ;; WinGetPos, winX, winY
    ;; WinMove, ahk_id %whnd%, , winX+1, winY
    ;; WinMove, ahk_id %whnd%, , winX, winY
}

ExitApp


get_script_parameters(){
    global
    static Script_Parameters := Object()

    if ("" == Script_Parameters.MaxIndex()) {
        Loop, %0%
        {
            Script_Parameters.insert(%A_Index%)
        }
    }
    return Script_Parameters
}

emacs lisp

(defvar exec-path-shaking-the-window-of-ntemacs
  "~/shaking-the-window-of-ntemacs-to-enable-ime.exe")

(defun shaking-the-window-of-ntemacs (path &optional mouse-button)
  (with-temp-buffer
    (start-process "my-process" nil
                   path
                   (if mouse-button mouse-button "left")
                   )))

(if (and (eq window-system 'w32)
         (file-exists-p exec-path-shaking-the-window-of-ntemacs)
         )
    ;; (move-window-with-ahk path-move-window-with-ahk)
        (add-hook 'emacs-startup-hook '(lambda nil
                                     (shaking-the-window-of-ntemacs exec-path-shaking-the-window-of-ntemacs "right")))

  (message (concat "error: " exec-path-shaking-the-window-of-ntemacs " is not found.")))

*1:[asin:4774150029:detail]

*2:p.12