ChromeOSでEmacs Keybindを使う


ChromeOS上のchromeでemacsキーバインドを実現するextensionかつIMEをつくりました。興味ある方いたら使ってみてください。使い方は結構ややこしいです。
私はDevチャンネルで使っているのでそれ以外の環境で使ってみてくれる人いたらうれしいです。

できること

ChromeOS上のChromeのテキスト入力可能なところでのEmacs Likeなキー操作

サポートしているキーバインド

  • Ctrl+P (Up)
  • Ctrl+N (Down)
  • Ctrl+B (Left)
  • Ctrl+F (Right)
  • Ctrl+A (Home)
  • Ctrl+E (End)
  • Ctrl+D (Delete)
  • Ctrl+H (Backspace)
  • Ctrl+M (Enter)
  • Ctrl+K (Kill line to end)
  • Ctrl+W (Cut)
  • Ctrl+Y (Paste)

Extensionのインストール

使い方

こちらを熟読ください。

主に以下のような手順が必要です。
(画像はdevチャンネルで作ったのでstableとは違います。)

ここまでやって、Google Docsやgmailなどで試して見てください。

作るまでの顛末

Chromeとemacsキーバインドはけっこう相性が悪くて、ChromeのGoogle Docs上でemacs keybindを使えるのはMacOSくらい。
MacBookからPixelbookに乗り換えようと意気込んていたが、Emacsキーバインドが快適に使えるMacBookと比べると非常に使いづらい。

調べてみるといくつかツールがあるけど、Ctrl+PやCtrl+Nなど重要なバインドがChromeネイティブのショートカットとして拾われてしまいうまく動かない。

こういう記事も見つけたけど、私の環境ではうまく動かず。

私の目的としてはGoogle Docsが快適に操作できることが最優先。
Crostiniで動くLinuxアプリは大体Emacsキーバインド使えるので、Chromeさえなんとかなればよかった。

上記記事で紹介されている

をいじっているうちに、うまく行く方法を発見してゼロから作ることになった。chrome extensionもはじめて作った。

あと夏休みで時間があった。

実現方法

ChromeOSとChromeの制限をいかにかいくぐるか、という勝負。

chrome.commands を使ってショートカットの上書き

Emacsキーバインドで重要なCtrl+P, Ctrl+N, Ctrl+FなどはChromeがショートカットを使っているため、普通のツールでは上書きできない。
私が発見したのはchrome.commandsというextensionのAPIを使って、それにショートカットを設定するとChromeのショートカットを上書きできることだった。
ただ、ひとつのextensionは4つまでしかデフォルトのショートカットを設定できない。この制限はchromeのソースコードにベタがきされており変更不可能。
また、先述のChromeが使っている、Ctrl+P, N, Fなどはデフォルトでは登録できない。そこで手動で設定してもらうことにした。
manifest.json に以下のような感じで書いておくと、

{
  "commands": {
    "00-up": {
      "description": "Go Up (Ctrl+P)"
    },
    "01-down": {
      "description": "Go Down (Ctrl+N)"
    }
}

以下のような感じでjsで処理できる。

chrome.commands.onCommand.addListener(function (c) {
  switch (c) {
    case "00-up":
      sendEvent('ArrowUp');
      break;
    case "01-down":
      sendEvent('ArrowDown');
      break;
   ....
}

コマンド名に数字がついているのはショートカット設定ページで名前の順で勝手にソートされるので、任意の順位するため。

chrome.input.ime による入力処理

よく調べていないが、Chromeでキー入力をするにはIMEのAPIを使うしかないようだ。なのでIMEとして作ることになった。IMEを作るというとすごく大変そうだが、実際にはコードを1行も書かなくてもIMEにすることができる。IMEにするとテキストボックスなど文字入力が可能な状態でキーコードを送ることができる。
コードは以下のような感じ。

chrome.input.ime.sendKeyEvents({ "contextID": contextId, "keyData": [keyData] });

私が作ったextensionではこのchrome.input.ime.sendKeyEventsを使って仮想的にキーを入力することで各種ショートカットを実現している。
例えばCtrl+KShift + Endして、Ctrl+X (切り取り)することで実現している。これをショートカットからのchrome.commandsという普通IMEで使わないようなところから呼び出すことでemacs keybindを実現している。

manifest.jsonとmain.jsで合わせても200行もなく実現出来た。

出来ないこと

  • 今のところChrome上ででしか動かない。ChromeOS搭載の謎のテキストエディタなどでは動かない。chrome.commandsにはglobalなショートカットのオプションがあるがChromeOSでは動かない。
  • Ctrl+Spaceなど単純なキー入力で実現出来ないものはサポートしていない。がんばればできるかもだけど、Ctrl+Spaceは特にそもそもIME切り替えなので難しいだろう。
  • また、潰してしまったCtrl+Fなどのショートカットが使えない。必死で潰したのにないと今度は困る。これはなんとかしたいところだがやり方がわからない。
  • 日本語入力中に使えない。これはMozcを改造して自分でビルドすれば多分できる。Google DocsだとCtrl+Shift+Kで日本語入力できるので取り敢えずやらない。Qiitaを書くのに早速今困っているがなんとかなる。