Hatena::ブログ(Diary)

N->N->N

2017-02-24

mozc_emacs_helper を使う

mozc_emacs_helper は emacs から mozc を使用するための外部プログラム。

sudo apt-get install emacs-mozc-bin

emacs-mozc-bin パッケージは emacs への依存がないので emacs がまるごと付いてきたりしない。

mozc_emacs_helper プログラムとのやり取りは S 式で行う。

利用できるコマンドは以下のもの。

(EVENT_ID SendKey SESSION_ID KEY ...)
(EVENT_ID CreateSession)
(EVENT_ID DeleteSession SESSION_ID)

括弧の後にLF(\n)が必要です。KEY は整数値、バックスラッシュによるエスケープされた文字、またはキー。

ターミナルで実行すると以下のようになる。

> mozc_emacs_helper
((mozc-emacs-helper . t)(version . "2.17.2116.102")(config . ((preedit-method . roman))))
(1 CreateSession)
((emacs-event-id . 1)(emacs-session-id . 1)(output . ()))

グリーティングメッセージが出るので、まずセッションを作成する。応答でイベント ID とセッション ID が確認できる。

SendKey コマンドでキー押し下げを送信する。

(2 SendKey 1 "r")
((emacs-event-id . 2)(emacs-session-id . 1)
(output . (
    (id . "6309519535730520822")(mode . hiragana)(consumed . t)
    (preedit . (
        (cursor . 1)(segment 
            ((annotation . underline)(value . "r")(value-length . 1)(key . "r")))))
    (candidates . (
        (size . 1)(candidate ((index . 0)(value . "r")
            (annotation . (
                (description . "[半] アルファベット")))
            (id . 0)))
        (position . 0)(category . suggestion)(display-type . main)
        (footer . (
            (label . "Tabキーで選択")))
        (page-size . 9)))
    (status . (
        (activated . t)(mode . hiragana)(comeback-mode . hiragana)))
    (all-candidate-words . (
        (candidates 
            ((id . 0)(index . 0)(value . "r")(annotation . ((description . "[半] アルファベット")))))
            (category . suggestion)))
)))

(3 SendKey 1 "a")
((emacs-event-id . 3)(emacs-session-id . 1)
(output . (
    (id . "6309519535730520822")(mode . hiragana)(consumed . t)
    (preedit . (
        (cursor . 1)(segment 
            ((annotation . underline)(value . "ら")(value-length . 1)(key . "ら")))))
    (candidates . (
        (size . 3)(candidate 
            ((index . 0)(value . "楽")(annotation . ((deletable . t)))(id . 0))
            ((index . 1)(value . "ラフト")(annotation . ((description . "[全] カタカナ")(deletable . t)))(id . 1))
            ((index . 2)(value . "ライセンス")(annotation . ((description . "[全] カタカナ")(deletable . t)))(id . 2)))
        (position . 0)(category . suggestion)(display-type . main)
        (footer . ((label . "Tabキーで選択")))
        (page-size . 9)))
    (status . (
        (activated . t)(mode . hiragana)(comeback-mode . hiragana)))
    (all-candidate-words . (
        (candidates 
            ((id . 0)(index . 0)(key . "らく")(value . "楽")(annotation . ((deletable . t))))
            ((id . 1)(index . 1)(key . "らふと")(value . "ラフト")(annotation . ((description . "[全] カタカナ")(deletable . t))))
            ((id . 2)(index . 2)(key . "らいせんす")(value . "ライセンス")(annotation . ((description . "[全] カタカナ")(deletable . t)))))
        (category . suggestion)))
)))

(4 SendKey 1 space)
((emacs-event-id . 4)(emacs-session-id . 1)
(output . (
    (id . "6309519535730520822")(mode . hiragana)(consumed . t)
    (preedit . (
        (cursor . 1)(segment 
            ((annotation . highlight)(value . "ラ")(value-length . 1)(key . "ら")))
            (highlighted-position . 0)))
    (status . (
        (activated . t)(mode . hiragana)(comeback-mode . hiragana)))
    (all-candidate-words . (
        (focused-index . 0)(candidates 
            ((id . 0)(index . 0)(value . "ラ")(annotation . ((description . "[全] カタカナ"))))
            ((id . 1)(index . 1)(value . "ら")(annotation . ((description . "ひらがな"))))
            ((id . 2)(index . 2)(value . "等"))
            ((id . 3)(index . 3)(value . "羅"))
            ((id . 7)(index . 4)(value . "裸"))
            ((id . 8)(index . 5)(value . "拉"))
            ((id . 9)(index . 6)(value . "瘰"))
            ((id . 10)(index . 7)(value . "蘿"))
            ((id . 11)(index . 8)(value . "蠡"))
            ((id . 12)(index . 9)(value . "鑼"))
            ((id . 13)(index . 10)(value . "楽"))
            ((id . 15)(index . 11)(value . "良"))
            ((id . 16)(index . 12)(value . "樂")(annotation . ((description . "楽の旧字体"))))
            ((id . 17)(index . 13)(value . "浦"))
            ((id . 18)(index . 14)(value . "十"))
            ((id . 19)(index . 15)(value . "彰"))
            ((id . 20)(index . 16)(value . "晶"))
            ((id . 21)(index . 17)(value . "税"))
            ((id . 22)(index . 18)(value . "倉"))
            ((id . 23)(index . 19)(value . "螺"))
            ((id . 24)(index . 20)(value . "蘭"))
            ((id . 25)(index . 21)(value . "浪"))
            ((id . 26)(index . 22)(value . "篭")(annotation . ((description . "籠の略字"))))
            ((id . 27)(index . 23)(value . "籠")(annotation . ((description . "篭の印刷標準字体"))))
            ((id . 28)(index . 24)(value . "薇"))
            ((id . 29)(index . 25)(value . "邏"))
            ((id . 30)(index . 26)(value . "騾"))
            ((id . -3)(index . 27)(value . "ra")(annotation . ((description . "[半] アルファベット"))))
            ((id . -4)(index . 28)(value . "RA")(annotation . ((description . "[半] アルファベット"))))
            ((id . -6)(index . 29)(value . "Ra")(annotation . ((description . "[半] アルファベット"))))
            ((id . -7)(index . 30)(value . "ra")(annotation . ((description . "[全] アルファベット"))))
            ((id . -8)(index . 31)(value . "RA")(annotation . ((description . "[全] アルファベット"))))
            ((id . -10)(index . 32)(value . "Ra")(annotation . ((description . "[全] アルファベット"))))
            ((id . -11)(index . 33)(value . "ラ")(annotation . ((description . "[半] カタカナ")))))
        (category . conversion))))))

(5 SendKey 1 space)
((emacs-event-id . 5)(emacs-session-id . 1)
(output . (
    (id . "6309519535730520822")(mode . hiragana)(consumed . t)
    (preedit . (
        (cursor . 1)(segment 
            ((annotation . highlight)(value . "ら")(value-length . 1)(key . "ら")))
        (highlighted-position . 0)))
    (candidates . (
        (focused-index . 1)(size . 34)(candidate 
            ((index . 0)(value . "ラ")(annotation . ((description . "[全] カタカナ")(shortcut . "1")))(id . 0))
            ((index . 1)(value . "ら")(annotation . ((description . "ひらがな")(shortcut . "2")))(id . 1))
            ((index . 2)(value . "等")(annotation . ((shortcut . "3")))(id . 2))
            ((index . 3)(value . "羅")(annotation . ((shortcut . "4")))(id . 3))
            ((index . 4)(value . "裸")(annotation . ((shortcut . "5")))(id . 7))
            ((index . 5)(value . "拉")(annotation . ((shortcut . "6")))(id . 8))
            ((index . 6)(value . "瘰")(annotation . ((shortcut . "7")))(id . 9))
            ((index . 7)(value . "蘿")(annotation . ((shortcut . "8")))(id . 10))
            ((index . 8)(value . "蠡")(annotation . ((shortcut . "9")))(id . 11)))
        (position . 0)(category . conversion)(display-type . main)
        (footer . ((index-visible . t)(logo-visible . t)))(page-size . 9)))
    (status . ((activated . t)(mode . hiragana)(comeback-mode . hiragana)))
    (all-candidate-words . (
        (focused-index . 1)(candidates 
            ((id . 0)(index . 0)(value . "ラ")(annotation . ((description . "[全] カタカナ"))))
            ((id . 1)(index . 1)(value . "ら")(annotation . ((description . "ひらがな"))))
            ((id . 2)(index . 2)(value . "等"))
            ((id . 3)(index . 3)(value . "羅"))
            ((id . 7)(index . 4)(value . "裸"))
            ((id . 8)(index . 5)(value . "拉"))
            ((id . 9)(index . 6)(value . "瘰"))
            ((id . 10)(index . 7)(value . "蘿"))
            ((id . 11)(index . 8)(value . "蠡"))
            ((id . 12)(index . 9)(value . "鑼"))
            ((id . 13)(index . 10)(value . "楽"))
            ((id . 15)(index . 11)(value . "良"))
            ((id . 16)(index . 12)(value . "樂")(annotation . ((description . "楽の旧字体"))))
            ((id . 17)(index . 13)(value . "浦"))
            ((id . 18)(index . 14)(value . "十"))
            ((id . 19)(index . 15)(value . "彰"))
            ((id . 20)(index . 16)(value . "晶"))
            ((id . 21)(index . 17)(value . "税"))
            ((id . 22)(index . 18)(value . "倉"))
            ((id . 23)(index . 19)(value . "螺"))
            ((id . 24)(index . 20)(value . "蘭"))
            ((id . 25)(index . 21)(value . "浪"))
            ((id . 26)(index . 22)(value . "篭")(annotation . ((description . "籠の略字"))))
            ((id . 27)(index . 23)(value . "籠")(annotation . ((description . "篭の印刷標準字体"))))
            ((id . 28)(index . 24)(value . "薇"))
            ((id . 29)(index . 25)(value . "邏"))
            ((id . 30)(index . 26)(value . "騾"))
            ((id . -3)(index . 27)(value . "ra")(annotation . ((description . "[半] アルファベット"))))
            ((id . -4)(index . 28)(value . "RA")(annotation . ((description . "[半] アルファベット"))))
            ((id . -6)(index . 29)(value . "Ra")(annotation . ((description . "[半] アルファベット"))))
            ((id . -7)(index . 30)(value . "ra")(annotation . ((description . "[全] アルファベット"))))
            ((id . -8)(index . 31)(value . "RA")(annotation . ((description . "[全] アルファベット"))))
            ((id . -10)(index . 32)(value . "Ra")(annotation . ((description . "[全] アルファベット"))))
            ((id . -11)(index . 33)(value . "ラ")(annotation . ((description . "[半] カタカナ")))))
        (category . conversion)))
)))

(6 SendKey 1 enter)
((emacs-event-id . 6)(emacs-session-id . 1)
(output . (
    (id . "6309519535730520822")(mode . hiragana)(consumed . t)
    (result . (
        (type . string)(value . "ら")(key . "ら")))
    (status . (
        (activated . t)(mode . hiragana)(comeback-mode . hiragana)))
)))

これでr, a, space, space, enterと入力したことになる。

不要になったらセッションを削除する。

(4 DeleteSession 1)
((emacs-event-id . 7)(emacs-session-id . 1)(output . ()))

SendKey コマンドの引数には以下のものが指定できる。

Python の subprocess から実行すると communicate メソッドを一度呼び出すと stdin が close されてしまう。stdin に write することになる。読み出しは stdout と stderr でブロックされないように別スレッドで読み込んでタイムアウトなどが必要。