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
でいいと思うけどよく知らない。

Kenya Television Network

GTK の環境に対して定義できる設定のうち、[cci]gtk-key-theme-name[/cci] というものがあって、主にテキスト入力系のウィジェットのキーバインディングを変更することができる。で、これを [cci]Emacs[/cci] にすると、どのアプリケーションでもまあだいたいそんな感じの振る舞いをしてくれる。

これらのバインディングは [cci]/usr/share/themes/Emacs/[/cci] 以下の gtk2.0 と gtk3.0 用のそれぞれのファイルで定義される。[cci]gtk-key-theme-name[/cci] 自体はどこで定義するのかと言うと……実は複雑すぎてよく分からないのだが、Xfce であれば設定マネージャから設定エディタを呼び出して xsettings チャネルの Gtk -> KeyThemeName プロパティの値を Emacs にすればいい。

ただ、実に不思議なことがある。Chrome の各種のテキスト入力系ウィジェットも当然この影響を受けるのだけど、KeyThemeName プロパティを空に戻してもどういうわけか Emacs バインディングが残ったままになる。他のアプリケーションからは Emacs バインディングはスパッと消え失せるのだけど。Chrome 自身が独自にどこかにキャッシュしているの?

それと、うちの環境だと ^P ^N の代わりに ^K ^J でキャレットが上下方向に移動する。多分これ、自分でそうなるように定義したと思うのだけど(/usr/share/themes/Emacs/ 以下のファイルにはそういう定義はないので)、ホームのどこでそれを定義したのか全然覚えてない。定義したのかどうかも覚えてない。記憶力の危険が危ない。

Ubuntu 16.04

Ubuntu 16.04.1 LTS (Xenial Xerus) がリリースされうちのマシン(Xubuntu)にもアップグレード通知が来たのだが、困ったことがある。

現状 AMD 製 GPU の Linux 向けドライバには 3つの選択肢があり:

  • Radeon ドライバ: OSS で、あんまりハードウェアの性能は引き出せない。多分安定はしている
  • fglrx ドライバ: AMD 製のプロプラ。まあまあ性能を引き出してるのだと思うけど(あと設定が Catalyst による GUI で行えるので試行錯誤しやすい)、あんまり安定してない
  • amdgpu ドライバ: 最新の Linux カーネルの管理下にある OSS ドライバだが、AMD からの技術公開を受けて安定さと性能を両立している(という触れ込み)だが超ナウい GPU しか今のところサポートしていない

うちのマシンは GPU が AMD Radon HD 6320 というやつなのだけど、困ったことに AMD は 16.04 向けの fglrx を作らない宣言を出しているのであった。なので、今 16.04 にアップグレードすると Radeon ドライバか amdgpu ドライバを選択せざるを得ないのだけど、amdgpu は今のところ HD 6320 をサポートしていないので対象外(最終的にはもっと古い GPU もサポートすると言っているのだがいつかは不明)。そういうわけで Radeon ドライバが最終候補になるのだが。前述のとおりこれは OSS 原理主義者のためのものであって性能はいまいちなのである。

というわけで、16.04 にアップグレードしたくてもできない。はやく amdgpu が進歩してほしい。

change a IME state

あらゆるところですでに怨嗟の声が書き込まれまくっているので、特に新しく書くこともないのだけれど、iBus 1.5 で IME の状態を切り替えるという話。

つまるところ、IME のオン・オフを切り替えるために従来は IME 内の状態(”直接入力” と “ひらがな”)を操作していた。それが、システムに登録されたキーボードレイアウト(たとえば、US キーボードと mozc が有効なキーボード)自体を切り替えるようになったのである。”IME が有効なキーボードレイアウト” という概念が不自然で、この辺の移行が混乱しているのが文句の原因らしいのである。

個人的には、方式が変わること自体は別に文句はない。ちょこちょこっと設定しなおして、右 Alt キーで IME の状態をトグルできればそれで良いのです。ただ困るのはいずれの方式にしても微妙にストレスフルな不具合というか何と言うかがあるという点で:

まず iBus 1.5 デフォルトの、キーボードレイアウト自体の切り替え方式にした場合。この場合、レイアウトの切り替えに使うキーは iBus の設定ウィンドウ中に登録する。

  • 良い点: レイアウトの状態(≒ IME の状態)をシステムアイコンに反映させられる
  • 悪い点: iBus の設定の中の “すべてのアプリケーション間で同じインプットメソッドを共有する” をオンにすると、このようにブラウザ上で文章を書きつつ端末上の vim に切り替えた場合など、明らかに IME がオフであるべきアプリケーションでも IME がオンになっている状況が多発してとてもストレスが貯まる。
    そこで前述の設定をオフにすれば、レイアウトの状態はアプリケーションごとに独立するのでそれは解決するのだが、そのかわり IME をオンにした時の最初のプリエディットの最初の文字を取りこぼす現象が多発してこれはこれでものすごくストレスが貯まる。

そんなわけで、じゃあ “すべてのアプリケーション間で同じインプットメソッドを共有する” はオフにした上で、IME の状態はやっぱり IME 自身が管理したほうがいいんじゃないの? と思い、右 Alt キーは mozc が反応するように設定しなおしたのだが。

そうするとシステムアイコン上のキーボードレイアウトは常に単に mozc のアイコンが表示されるだけになり、現在の入力モードがわからない。いや入力モード自体は iBus のプロパティパネルとやらに表示されるのだが。これが表示される位置がなかなかめっちゃくちゃで、また表示を自動にすると表示から数秒後に自動的に消えてしまうし、常に表示にすれば常に邪魔くさいわけで、つまりフロート式のプロパティパネルという仕様自体が間違っていると思うのです。

iBus のプロパティパネルのシステムアイコン版が、システムアイコンのキーボードレイアウトアイコンの隣に表示されればそれが最も現実的な解だと思うのだけれど。それをするためにどこの設定をどーすればいいのかわからないわけでストレスが貯まる。

ストレスをいくら貯めたところでポイントには変換できないのである。どうにかならないのかしらん。