skk is … #3

・カタカナを入力する簡便なショートカットとして、見出し語を入力して Q を押すとカナに変換されて確定する仕様がある。これを「ゔぁいおりん」という入力について適用すると「ゔァイオリン」になってしまう。

これは元をたどればもともと skk が euc-jp エンコーディングで動いていたためで、Unicode にしかない濁点つきの「ゔ」を知らないからなのだろう。しかし今動いてる skk の本体は vala で書かれた libskk であり、基本となるエンコーディングもたぶん utf-8 だろうからそういうしがらみは実はないはずだ。

ということで追ってみたが https://github.com/ueno/libskk/blob/master/libskk/util.vala#L43 以下に定義されている変換テーブルに「ゔ」のエントリがないからだと思う。「う゛」はある。このテーブルもキーマッピングやローマ字同様に json ファイルから読み込むようにしてほしい…。

・libskk 内のいじった設定を反映させるために fcitx を再起動するのだが、その直後に高い確率で thunar がクラッシュする。ふふ、お前マジぶっころがすぞ。

・fcitx-skk の設定で初期入力モードを「直接入力」にしても反映されない。常にひらがな入力で開始する。

・現在の入力モードを通知領域に表示してもらえるととっても嬉しいのだけど、そうなってくれない。そのかわりに状態パネルなるものを常に表示するようにすると、そこに現れる。まあ…それでもいいんだけど…。いや良くない。邪魔だ。

・xkb で右 alt を F20 に交換している。そのキーにひらがな入力に入るコマンドを割り当てたいが、なぜか動作しない。どういうキーを受けてどういうマッピングをしたのかをレポートするログ機能が libskk にほしい。

skk is … #2

絵文字の変換を行うために
https://github.com/uasi/skk-emoji-jisyo
の SKK 辞書を使いたい。ダウンロードして、dictionary_list に追記する。

file=$FCITX_CONFIG_DIR/SKK-JISYO.emoji.utf8,mode=readonly,encoding=UTF-8,type=file

が、認識してくれない。なんで…? と思ってソースを見てみたら
https://gitlab.com/fcitx/fcitx-skk/blob/master/src/skk.c#L196
なるほど readonly の場合は $FCITX_CONFIG_DIR の展開をしていない。というか、この関数自体の文字列処理とメモリ管理の書き方がなんとなく危うい感じがする…。

そういうわけで仕方ないのでベタに書いて認識。

file=/home/akahuku/devel/ref/skk/skk-emoji-jisyo/SKK-JISYO.emoji.utf8,mode=readonly,encoding=UTF-8,type=file

その他の環境変数や “~” はどうなんだろうか。このパス名は libskk を経由して GLib の File_for_path() という立派な関数に渡されるのでそこでなんかうまいことしてくれるのかもしれない。試してない。

しかし認識したのはよいものの、入力中に “/” で入る見出し語をアルファベットで編集するモードでこの辞書内の見出しを補完できない。

うーむ。まあこの補完って先頭一致なのでできたとしてもあんまり嬉しくはないのだけど。例えば heart だけでも

black_heart
blue_heart
broken_heart
couple_with_heart
couple_with_heart_man_man
couple_with_heart_woman_man
couple_with_heart_woman_woman
gift_heart
green_heart
heart
heart_decoration
heart_eyes
heart_eyes_cat
heartbeat
heartpulse
hearts
heavy_heart_exclamation
kissing_heart
purple_heart
revolving_hearts
sparkling_heart
two_hearts
yellow_heart

こんな感じで先頭だったり真ん中だったり末尾だったり単語中にあったりごちゃごちゃなので。

skk is …

mecab-skkserv のテスト中、キー押下から反応が返ってくるまでやたら時間がかかる現象に陥ったことが一度あると前の記事に書いた。

調べてみると、この原因はまさに mecab-skkserv だった。発生する条件は、見出し語の編集中に Ctrl+I もしくは Tab を押す、つまり補完を開始するとそういう状態になる。

この補完機能は skkserv のプロトコルで言うと 4 に当たるのだけど、mecab-skkserv.cpp のメインループでそれに対応する応答を行っていないため、fcitx 側(正確には libskk)が応答を延々待ち続けることになるのだろう。知らないコマンドを無視する mecab-skkserv の問題とも言えるし、レスポンスを読む際にタイムアウトを考慮しない呼び出し側の問題とも言える。

--- mecab-skkserv-original.cpp	2020-01-17 17:37:19.897237779 +0900
+++ mecab-skkserv.cpp	2020-01-17 17:38:26.822432515 +0900
@@ -33,20 +33,10 @@
 #include <stdexcept>
 #include <set>
 
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
-#if defined HAVE_GETOPT_H && defined HAVE_GETOPT_LONG
-#include <getopt.h>
-#else
-#include "getopt.h"
-#endif
-
 #define STDIN (fileno(stdin))
 #define BUFSIZE 8192
 #define DEFAULT_CAND_SIZE 20
@@ -155,6 +145,10 @@
       case '3':
 	std::cout << "localhost:127.0.0.1: " << std::flush;
 	break;
+       
+      case '4':
+	std::cout << '4' << std::endl;
+	break;
       }
     }
 

というわけで修正自体は数行付け足すだけでいいのだけど、このパッチを誰にどう投げればいいのかよく分からない。助けて偉い人。

mozc is … #4

ということで mecab-skkserv をビルドする。

mecab 本体のビルド

まず mecab 本体を落としてきて普通にビルドする。特に記すことはない。このページで提供されている辞書は mecab-skkserv には不要なので作っても作らなくてもいい。
https://taku910.github.io/mecab/

mecab-skkserv のビルド

http://chasen.org/~taku/software/mecab-skkserv/
おそらく幾つかの点でコンパイルエラーになるので

  • mecab-skkserv.cpp で getopt.h を #include している箇所を削除
  • dicrc に cost-factor = 700 とかを追記する(値は700〜800で任意とのこと)

等々を施す必要があるだろう。ちなみにビルドの際に辞書も構築されるが、特に ./configure で指定しなければ euc-jp エンコーディングになる。

systemd ユニットの作成

mecab-skkserv 本体のインストールまで済んだら次は xinetd か tcpserver に登録することになっているが、2020年の現在はそれらではなく systemd の話になる。以下のファイルを新規作成する。

/etc/systemd/system/mecab-skkserv.socket ファイル

[Unit]
Description=mecab-skkserv socket

[Socket]
ListenStream=1178
Accept=yes

[Install]
WantedBy=sockets.target

/etc/systemd/system/mecab-skkserv@.service ファイル

[Unit]
Description=mecab-skkserv service
Requires=mecab-skkserv.socket

[Service]
Type=simple
ExecStart=/usr/local/bin/mecab-skkserv
StandardInput=socket
StandardError=journal

[Install]
WantedBy=multi-user.target

systemd に対して有効にする。この有効化はマシン再起動をまたいでも永続的である。

$ systemctl enable mecab-skkserv.socket
$ systemctl start mecab-skkserv.socket
$ systemctl status mecab-skkserv.socket

この設定だと外のマシンからの接続も受け付けるので、拒否する必要があるなら iptables とかのレベルでうまいことする。

この状態でちゃんと動いてるかどうかは例えば

$ echo "2 " | nc localhost 1178

などとして確認できる。mecab-skkserv のバージョン情報が返ってくればとりあえず接続の受付と起動は正常。

fcitx-skk に対して mecab-skkserv を辞書として登録する

~/.config/fcitx/skk/dictionary_list に以下の行を追加

type=server,host=localhost,port=1178

このファイルでは辞書の指定の順番が重要な気がするが、SKK_JISYO.* の上に置く場合と下に置く場合でどう違うのかは試してない。

また、上記の通り普通に mecab-skkserv をビルドすると euc-jp エンコーディングの辞書が構築される。skkserv プロトコル自体が euc-jp で動くことになっているのでそれで正しいのだが、絵文字など unicode でしか表現できない文字を辞書に含めることができなくなる。その場合辞書を utf-8 で構築し、dictionary_list には

type=server,host=localhost,port=1178,encoding=UTF-8

などと指定すれば良い。

あとは fcitx を再起動すれば普通に使えるようになる。素の SKK だと Watashi<spc>noNamae<spc>haNakano<spc>desu. などと打っていたものが Watashino<spc>Namaeha<spc>Nakanodesu. くらいまでシンプルになる。いやこれはあんまり良い例じゃないな。とにかく送り仮名を気にする必要がほとんどの場合なくなる。

困った点としては

  • skkserv の向う側の辞書は一切変換の学習をしない。学習を skkserv 辞書にフィードバックする仕様自体がプロトコルにない?
  • たまにキー押下からレスポンスが返ってくるまで数十秒かかる状態に陥ることがある。たまにというか今まで1回だけそうなった。原因不明
  • 素の SKK に比べると、変換のレスポンスはほんのわずかに遅れる感じはする。ほんの0.1〜0.2秒ほど。慣れの範囲だろう

とはいえ普通に快適なので、当分 mozc を使うことはないだろう。

mozc is … #3

もう少し SKK で遊んでみよう。SKK といえば辞書をネットワーク越しに持てるのが特徴のひとつである。そのへんを追いかけてみる。skkserv なんて15年くらい前の話題なので2周くらい遅れてるわけだが気にしてはいけない。

さてコンピュータ上で日本語を入力する現代的かつ一般的な方式というのは、文字入力できるフィールドにおける挿入ポイントに対してフロントエンドとなるインターフェースが用意されていて、そのプリエディットバッファ内での入力と文節単位の(漢字)変換結果の選択をおこなったのち、最終的な変換結果全体をフィールドに送出するというものだ。

しかし、この方式が本当に日本語入力の完成された到達点なのか? と言うとそうは思えない。なんか日本語変換してるときって言い様のないストレスを感じません? この原因はプリエディットというものの存在にあると思う。正確に言えばプリエディットという非常にモーダル性の高いインターフェースに役割を持たせすぎて、そのライフタイムを長くさせる設計が良くない。

思うに、プリエディットがアクティブで、そこにいろんなものが溜まってる状態というのは、いわば便秘に苛まれている状態そのものなんだろう。その状態のストレスがどんなものか、説明するまでもない。食べたものも入力したものも体内での役目を終えたら即出力されるのがストレスのない生き方なのは自明の理なのに、プリエディットに頼りすぎるという全く正反対の食生活を押し付けてくる現代の日本語入力インターフェースは健康的にも邪悪というより他はない。

そういう観点で SKK を見てみると、SKK の本質からは若干ずれている気がするが、漢字変換の必要がない文字種についてはプリエディットを経ずに直接入力できるという仕様が、SKK を通して入力する際の妙な気楽さ、ストレスの低さに貢献している要素のひとつであるように思える。これは非常に重要。

一方で、SKK の本質である漢字変換の際に送り仮名の開始位置を明示しなければならない仕様は、それが手書きに通じて良いと肯定する意見もあるが、やはりさすがに使いやすさをスポイルしている要素だと言わざるを得ないと思う。ここがなんとかなるとかなり嬉しい。

そういうことで最初に戻るのだが、SKK の場合辞書の部分が分離されていて後から追加できたり、見出し語から対応する語を返す仕様さえ満たしていれば他はなんでもありだったりするので、それを利用してもう少し楽に変換したい。具体的には mecab-skkserv を入れたい。mecab-skkserv はその名の通り mecab をバックエンドに持つ辞書で、これにより送り仮名を意識することなく変換することができるはずだ。ただし、mecab-skkserv の説明で「疑似的に連文節変換ができる」と言われることがあるが、SKK にも mecab-skkserv にも連文節を編集する機能はないのでそれはあまり正しくはない。素の SKK が漢字列とそれに付随する送り仮名の頭という風変わりな単位で変換するのに比較してより自然に文節単位で変換できるようにはなる。

mozc is … #2

日本語を入力するために mozc を使用しているわけなのだが、これが何だかよく分からないが微妙にヘンなのがすごく気になる。たとえば「〜方が」とか「〜という奴」などと打っても、「方」や「奴」を絶対に変換してくれない。つまり、それらを文節の区切りの開始として扱ってくれない。そして文節を指定しなおしてもそれを絶対に学習してくれない。どうしてなの。ハードコーディングされてるの?

そういうわけなので SKK に乗り換えてしまった。

基本的に特に設定を変えずに使ってるが、ローマ字変換テーブルだけちょっといじった。

$ mkdir -p ~/.config/libskk/rules/default-ex
$ cp -R /usr/share/libskk/rules/default/* ~/.config/libskk/rules/default-ex/
$ vim ~/.config/libskk/rules/default-ex/metadata.json
$ vim ~/.config/libskk/rules/rom-kana/default.json
--- /usr/share/libskk/rules/default/rom-kana/default.json	2018-04-03 21:32:28.000000000 +0900
+++ /home/akahuku/.config/libskk/rules/default-ex/rom-kana/default.json	2020-01-15 02:37:30.609068213 +0900
@@ -178,11 +178,11 @@
             "tyu": ["", "ちゅ" ],
             "u": ["", "う" ],
             "vv": ["v", "っ" ],
-            "va": ["", "う゛ぁ" ],
-            "ve": ["", "う゛ぇ" ],
-            "vi": ["", "う゛ぃ" ],
-            "vo": ["", "う゛ぉ" ],
-            "vu": ["", "う゛" ],
+            "va": ["", "ゔぁ" ],
+            "ve": ["", "ゔぇ" ],
+            "vi": ["", "ゔぃ" ],
+            "vo": ["", "ゔぉ" ],
+            "vu": ["", "ゔ" ],
             "ww": ["w", "っ" ],
             "wa": ["", "わ" ],
             "we": ["", "うぇ" ],
@@ -211,6 +211,7 @@
             "yo": ["", "よ" ],
             "yu": ["", "ゆ" ],
             "zz": ["z", "っ" ],
+            "z ": ["", " " ],
             "z,": ["", "‥" ],
             "z-": ["", "〜" ],
             "z.": ["", "…" ],
@@ -235,8 +236,12 @@
             ":": ["", ":" ],
             ";": ["", ";" ],
             "?": ["", "?" ],
+            "!": ["", "!" ],
+            "~": ["", "〜" ],
             "[": ["", "「" ],
-            "]": ["", "」" ]
+            "]": ["", "」" ],
+            "(": ["", "(" ],
+            ")": ["", ")" ]
         }
     }
 }

あとは fcitx を再起動して SKK の設定から新しく作ったルールを選び直す。ただ、SKK の辞書マネージャが明らかにちゃんと動いてないっぽいのが気になる。

まあこの GUI は使わず、タイピング方式は ~/.config/fcitx/skk/rule を、辞書のリストは ~/.config/fcitx/skk/dictionary_list を直接編集すればいいだろう。ちなみに fcitx に設定を再リロードさせるには fcitx-remote -r とすればいい。

I did nothing but

今日日のソフトウェアは自動的にアップデートが行われるものが少なくないので、「何もしてないのに壊れた」ということが結構起こる。数日前から gimp が起動しなくなってしまった。

dmesg を見てみると、何やら AppArmor のエラーのようだ。また、snapcraft のフォーラムにも同じような話題が投稿されている。しかし解決には至ってないようだ。

$ snap list gimp --all
Name  Version  Rev  Tracking  Publisher     Notes
gimp  2.10.12  189  stable    snapcrafters  disabled
gimp  2.10.12  227  stable    snapcrafters  -

$ snap info gimp
name:      gimp
summary:   GNU Image Manipulation Program
publisher: Snapcrafters
contact:   https://github.com/snapcrafters/gimp/issues
license:   unset
description: |
  Whether you are a graphic designer, photographer, illustrator, or scientist, GIMP provides you
  with sophisticated tools to get your job done. You can further enhance your productivity with GIMP
  thanks to many customization options and 3rd party plugins.
  
  This snap is maintained by the Snapcrafters community, and is not necessarily endorsed or
  officially maintained by the upstream developers.
commands:
  - gimp
snap-id:      KDHYbyuzZukmLhiogKiUksByRhXD2gYV
tracking:     stable
refresh-date: today at 03:52 JST
channels:
  stable:    2.10.12 2020-01-10 (227) 429MB -
  candidate: 2.10.14 2020-01-12 (243) 179MB -
  beta:      ↑                              
  edge:      2.10.14 2020-01-10 (243) 179MB -
installed:   2.10.12            (189) 229MB -

なるほど確かに数日前に最新版になっているらしい。最新だけど動かない。ダメじゃん。というわけで

$ sudo snap revert gimp                                                                                                                                                                   gimp reverted to 2.10.12

とこんな感じでひとつ前に戻すと起動した。

Installing log: Ubuntu Server 18.04

apacheとgitリポジトリを保持しているUbuntu Serverを動かしているVirtualBoxを動かしているWindows10マシンがこの夏を乗り越えられずに寿命を迎えた。享年13なので大往生なんだろうか。さて、どうしようかな。

ということで適当なノートにUbuntu Serverを入れ直したい。仮想じゃなくなる。

ところでUbuntu Server 18.04.3をインストールしてもOperating system not found的なエラーになって起動しない。unetbootinではなく、Ubuntu公式のブータブルUSB作成ツールで作ってそこからインストールしても起動しない。はて…? 試しにXubuntu desktop 18.04をインストールしてみるとそれは起動する。うーん入れたいのはserverの方なんだけどな…まあ…いいかな! やり直すのめんどくさいし(雑な仕事)。

たぶん16.04とかなら入って、そこからアップグレードさせるのが正解だったのだろうと思うけど色々入れちゃったので後の祭り。そういうわけでdesktop OSをサーバ代わりに使うアホな人が一人誕生したのだった。

From crying 16yo to grieving 18yo #2

以前 xubuntu を 16.04 から 18.04 にアップグレードして以来、LightDM のログインスクリーンでパスワード打ち込んでもログインできず、オンスクリーンキーボードを経由せざるを得ない現象が発生してとても不便。

/var/log/lightdm/lightdm.log を見ていたら、起動時に読み込まれる設定ファイルの中に /usr/share/lightdm/lightdm.conf.d/50-xubuntu-numlock.conf というものがあった。はーなるほど numlock がかかってるのね。

ちなみにこの設定ファイルは xubuntu-numlockx を呼び出しているだけなのだが、このファイルは /etc/X11/Xsession.d/55numlockx への薄いラッパでしかない。 55numlockx はシェルスクリプトで、/etc/default/numlockx に記述されている設定に従って X が起動する際の numlock キーの状態を変更するようだ。設定が auto の場合は実行マシンがラップトップかどうかとか、接続されているデバイスを見てよしなにしてくれる。

ということで、/etc/default/numlockx における設定を NUMLOCK=auto から NUMLOCK=off に変更。

不具合なってた理由はつまり、55numlockx 内で USB キーボードが接続されているかを検知し、接続されていたら有無を言わさず numlock をオンにするようになっているからだ。うちのキーボードは USB 接続だが、テンキーがないタイプなのであった。そのケースを想定していない。

 * * *

ところでこの PC は設定で10分放置するとディスプレイを消灯するようにしているのだが、実際にはそれが無視される状態が続いていた。関係あるのかないのかよく分からないのだが、上記の変更を施したらなぜかその設定も反映されるようになってしまった。なんで…?

一応記録のために書いておくと上記の変更の他に /etc/lightdm/lightdm.conf.d/10-xubuntu.conf も以下のような感じで変更してある:

--- 10-xubuntu.conf.old
+++ 10-xubuntu.conf
@@ -1,2 +1,2 @@
-[SeatDefaults]
+[Seat:*]
user-session=xubuntu

でもいずれにしても、電源周りには関係なさそうで、謎。まあ、いっか。

Kenya Television Network #2

よく調べてみたら、Chromeに残ってしまうEmacsぽいキーバインドはcVimのデフォルトの動作だった。なーんだ、そりゃ確かに自分で定義した覚えがないわけだ。記憶力ヤバくなかった。

しかしそうすると、テキスト入力系ウィジェットへの追加のキーバインディングが複数の箇所にまたがってるのがなんだか居心地が悪い。gtk のレベルで定義したほうがグローバルに使えるし、そっちに統一しようかな。

cVim が定義するバインディングは以下の通り。

<C-i> move cursor to the beginning of the line
<C-e> move cursor to the end of the line
<C-u> delete to the beginning of the line
<C-o> delete to the end of the line
<C-y> delete back one word
<C-p> delete forward one word
<C-h> move cursor back one word
<C-l> move cursor forward one word
<C-f> move cursor forward one letter
<C-b> move cursor back one letter
<C-j> move cursor forward one line
<C-k> move cursor back one line

この内多用しているのは <C-i>、<C-e>、<C-u>、<C-f>、<C-b>、<C-j>、<C-k> くらい。これらを gtk のバインディングに移植すればいい。そして、cvimrc 側では [cci]iunmapAll[/cci] して、テキスト入力系ウィジェットへのバインディングをすべて削除する。

さて次に gtk 側で、自前のバインディングを定義する。

$ cd ~
$ mkdir .themes
$ cd .themes
$ cp -r /usr/share/themes/Emacs .
$ mv Emacs MyBindings

てな感じでホームに Emacs の定義をコピーし、必要な箇所をいじる。ところで gtk と言っても 2.0 系と 3.0 系があり、アプリケーションがどちらのバージョンのライブラリを参照しているかは傍目にはよく分からない(新しめのアプリケーションはまあ 3.0 系と考えていいんだろうけど)。Chrome の場合は

  • /usr/bin/google-chrome (/etc/alternatives/google-chrome へのシンボリックリンク)
  • → /etc/alternatives/google-chrome (/usr/bin/google-chrome-stable へのシンボリックリンク)
  • → /usr/bin/google-chrome-stable (/opt/google/chrome/google-chrome へのシンボリックリンク)
  • → /opt/google/chrome/google-chrome (シェルスクリプトであり、/opt/google/chrome/chrome を exec する)

つまり最終的に実行される実行形式は /opt/google/chrome/chrome なので、これを ldd にかける:

$ ldd /opt/google/chrome/chrome | grep gtk
libgtk-3.so.0 => /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 (0x00007f99fa5cc000)

chrome は gtk-3.0 の方のバインディングを参照することが確認できた。ということでまずは MyBindings/gtk-3.0/gtk-keys.css をいじろう。このファイルは例えば

@binding-set gtk-emacs-text-entry
{
bind "b" { "move-cursor" (logical-positions, -1, 0) };
bind "b" { "move-cursor" (logical-positions, -1, 1) };
bind "f" { "move-cursor" (logical-positions, 1, 0) };
bind "f" { "move-cursor" (logical-positions, 1, 1) };

bind "b" { "move-cursor" (words, -1, 0) };
bind "b" { "move-cursor" (words, -1, 1) };
bind "f" { "move-cursor" (words, 1, 0) };
bind "f" { "move-cursor" (words, 1, 1) };

bind "a" { "move-cursor" (paragraph-ends, -1, 0) };
bind "a" { "move-cursor" (paragraph-ends, -1, 1) };
bind "e" { "move-cursor" (paragraph-ends, 1, 0) };
bind "e" { "move-cursor" (paragraph-ends, 1, 1) };

bind "w" { "cut-clipboard" () };
bind "y" { "paste-clipboard" () };

bind "d" { "delete-from-cursor" (chars, 1) };
bind "d" { "delete-from-cursor" (word-ends, 1) };
bind "k" { "delete-from-cursor" (paragraph-ends, 1) };
bind "backslash" { "delete-from-cursor" (whitespace, 1) };

bind "space" { "delete-from-cursor" (whitespace, 1)
"insert-at-cursor" (" ") };
bind "KP_Space" { "delete-from-cursor" (whitespace, 1)
"insert-at-cursor" (" ") };
/*
* Some non-Emacs keybindings people are attached to
*/
bind "u" { "move-cursor" (paragraph-ends, -1, 0)
"delete-from-cursor" (paragraph-ends, 1) };

bind "h" { "delete-from-cursor" (chars, -1) };
bind "w" { "delete-from-cursor" (word-ends, -1) };
}

entry {
-gtk-key-bindings: gtk-emacs-text-entry;
}

という感じになっていて、@binding-set で様々なバインディングを定義し、entry { -gtk-key-bindings: [name] } で割り当てる。binding-set に与える名前はそのスコープがよくわからないが、まあユニークなものにしておいたほうがいいんじゃないかな? 一方 entry (GtkEntry) は 1行入力のウィジェットのこと、textview (GtkTextView) は複数入力のウィジェットのことだ。それぞれに対して呼び出せる move-cursor や delete-from-cursor などの定義は以下を参照:

さて cVim のバインディングを持ってくる際、いくつか衝突する箇所がある。

  • cVim での ^U はカーソルから前方へ、行頭までを削除する。gtk ではカーソル行が位置する物理行全体を削除する。どちらを採るべきか?
  • cVim ではカーソルを行頭へ移動するのは ^I だが、gtk では Emacs にそのまま倣って ^A である。おそらく cVim は ^A = 全選択というジェネリックな UI に妥協して ^I に移動させたんだと思う。どちらを採るべきか? ちなみに gtk の Emacs バインディングでは全選択は ^/ で行える

そんなこんなをアレコレしたら、同じような変更を gtk-2.0/gtkrc にも施したら設定エディタの Gtk -> keyThemeName に新しく作ったテーマ名を与える。または、端末から
$ xfconf-query -c xsettings -p /Gtk/KeyThemeName -s MyBindings
な感じ。xfce ではないデスクトップ環境の場合は
$ gsettings set org.gnome.desktop.interface gtk-key-theme MyBindings
でいいと思うけどよく知らない。