Chrome で Emacs の kill-region 相当のことがしたくて extension を作ってみた

メインで使っているブラウザを Firefox から Chrome に乗り変えてからだいぶ経ったんですが、未だに不満なことが2つあります。
1つは browser.sessionstore.restore_on_demand に相当する機能がないこと、もう1つは Firemacs や KeySnail のような extension がないこと。

Chrome に乗り換えてからブラウザでテキストを編集するということがめっきり減りました。ホームポジションのままテキストの一部を選択して切り取ることができないのが苦痛でしょーがなかったからです。
^K でクリップボードにコピーされなかったり、^Y でクリップボードの内容を貼り付けられなかったりするのも苦痛でした。

というわけで、Chrome でそれらの機能を実現するための extension を作ってみました。kill-region は Mac でしか動かないと思います。開発時に使った Chrome のバージョンは 35.0.1916.114 です。

https://github.com/abicky/chemacs

課題

ちょっと調べた感じだと次のような課題があります・・・

  • KeyboardEvent を作成して dispatch してもイベントが発火するだけで実際の入力は行われない
    • ^K の keydown event で現在の位置から末尾まで選択して Command+X を実行するということができないし、マークをセットしてからの ^N の keydown event で Shift+down を発火させるということもできない
  • テキストを選択中の場合、現在のカーソルの位置を知る術がない(たぶん)
    • 現在のカーソルの位置を知る常套手段としては KeyboardEvent#selectionStart があるが、テキストを選択中の場合は使えないのでマークをセットした後にリージョンをハイライトさせようと思ってもできない
  • Event#preventDefault を実行しようとも Command+W の挙動を変えることができない
    • Command+W をリージョンのコピーに割り当てることができない
  • JavaScript でテキストの内容を変更しても編集の履歴が残らない(当たり前だけど・・・)
    • 自前で履歴を管理するしかない?(処理が煩雑になってメモリ使用量もすごいことになりそう・・・)

ハマったこと

上記のことは無理そうだなぁと思って諦めたんですが、他にもハマったことがありました。

document.execCommand(‘paste’) の使い方がわからない

ご丁寧に permission の説明には document.execCommand(‘paste’) を使うには “clipboardRead” が必要と書いてあるのに、肝心の使い方はさっぱりわかりません。
どうも background page で textarea を用意して、それに対して document.execCommand(‘paste’) を実行し、textarea.value でクリップボードの内容を取得して content script に渡すのが正しい使い方みたいです・・・。(面倒臭い!!)

cf. js/background.js#L27-L34

空のテキストエリアで document.execCommand(‘paste’) を実行しても最後の空行をペーストしてくれない

最初は次のようなコードを書いていたんですが、これだとクリップボードの内容の最後が空行の場合に空行が無視されてしまいました。

function getClipboardContent() {
    textarea.value = '';
    textarea.select();
    document.execCommand('paste');
    return textarea.value;
}

空のテキストエリアでなければちゃんと最後の空行も反映されるようなので、最初に textarea.value の値をスペース1つにして、最後にそのスペースを削ることでクリップボードの内容を返すように変更しました。

chrome.commands のキーが反映されない

最初の manifest.json の記述をミスった状態で extension をロードすると、修正してリロードしてもキーが反映されません。chrome://extensions/ の一番下にある Keyboard shortcuts で個別に割り当てるか、一度 extension を削除してリロードしないと反映されないみたいです。

cf. chrome.commands keyboard shortcuts not working for me - Stack Overflow

chrome.commands で space を指定できない

chrome.commands なんてのがあるみたいなんで、最初はショートカットキーの全てをこれで記述しようとしていたんですが、Ctrl+SPACE が割り当てられなくて断念しました。

Supported keys: A-Z, 0-9, Comma, Period, Home, End, PageUp, PageDown, Insert, Delete, Arrow keys (Up, Down, Left, Right) and the Media Keys (MediaNextTrack, MediaPlayPause, MediaPrevTrack, MediaStop).

chrome.commands - Google Chrome

何はともあれ、Chrome でのテキスト編集のストレスがだいぶ解消されそうです!