[Chrome] ユーザースクリプトで自作ショートカットキーを追加する

Chromeでユーザースクリプトとして自作のショートカットキーを追加したかったのですが、色々ハマりポイントがあったのでメモ。

# 要件

- 元ページで定義されているショートカットキーに追加する形（元のショートカットキーも使えるようにする）
- 元ページで使われている関数や変数を自作スクリプト内で利用できる

が目標。

#Chromeへのユーザースクリプトの追加の仕方
まずはChromeへのスクリプトの追加方法について。
<ol><li>ユーザースクリプトを組む(***.js)
<li>マニフェストファイル(manifest.json)を記述

```js:manifest.json
{
     "manifest_version":2, // 2で固定
     "version":"1.0",      // スクリプトのバージョン
     "name": "スクリプト名",
     "content_scripts": [
         {
             "js": ["***.js"],              // スクリプトのファイル名
             "matches": ["http://example.com/*"] // スクリプトを適応したいURLパターン
         }
     ]
}
```
<li>適当なディレクトリを作成し、上記2ファイルを入れる
<li><chrome://extensions/>を表示し、作成したディレクトリをドラッグ＆ドロップ
</ol>

参考：
[Chromeでユーザースクリプトを使う別の方法 - 公的内省](http://d.hatena.ne.jp/superstring04/20140614/1402777509)
[Chrome 拡張機能のマニフェストファイルの書き方 - Qiita](http://qiita.com/mdstoy/items/9866544e37987337dc79)

#ショートカットキーを追加するスクリプトの組み方
冒頭で提示した要件

- 元ページで定義されているショートカットキーに追加する形（元のショートカットキーも使えるようにする）
- 元ページで使われている関数や変数を自作スクリプト内で利用できる

を満たす為に、

- イベントの追加にはaddEventListnerを使う
- スクリプトをDOMに挿入して動かす

事がポイントになります。
その点を踏まえて書いたスクリプトがこちら。

```js:script.js
(function(callback) {
	var script = document.createElement("script");
	script.textContent = "(" + callback.toString() + ")();";
	document.body.appendChild(script);
})(function(){
	function canselEvent(e){
		e.stopPropagation();
		e.preventDefault();
		return false;
	}
	document.addEventListener("keydown", function(e) {
			switch(e.which){
					case *:			 		// *: キーコードを指定
						hoge(fuga);			// 処理を記述
						canselEvent(e);		// イベント伝播をキャンセル
						break;
					case *:
						hogehoge();
						canselEvent(e);
						break;
					/* 以下適宜追加 */
				}
		});
});
```

コードをざっくりと解説すると、

```js
(function(callback) {
	var script = document.createElement("script");
	script.textContent = "(" + callback.toString() + ")();";
	document.body.appendChild(script);
})(
	// 省略
);
```

この部分は省略部分のコードをscript要素化してDOMに挿入するという作業を行っています。
これにより元ページのDOM構築が終わった後にスクリプトが読み込まれるので、自作スクリプト内で元ページで使われている関数・変数が利用可能になります。

```js
function canselEvent(e){
	e.stopPropagation();
	e.preventDefault();
	return false;
}
```
イベント伝播キャンセル用の関数を定義しています。
switch文の後にキャンセル処理を書いてしまうと、Chrome自体のショートカットキーが使えなくなってしまうため、
関数を用意してそれぞれのbreakの前に処理を行うようにしています。

```js
document.addEventListener("keydown", function(e) {
		switch(e.which){
				case *:			 		// *: キーコードを指定
					hoge(fuga);			// 処理を記述
					canselEvent(e);		// イベント伝播をキャンセル
					break;
				case *:
					hogehoge();
					canselEvent(e);
					break;
				/* 以下適宜追加 */
			}
	});
```
keydownイベントリスナーを追加し、自作ショートカットキーを定義します。
Chromeでは[KeyboardEvent.which](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)で押されたキーコードを取得できるので、switchに渡して分岐。
ちなみに、Chrome以外では[KeyboardEvent.KeyCode](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)だったりします。
クロスブラウザ対応したい場合には、
`(window.event) ? e.keyCode : e.which`みたいにしてやると良いみたいです。
各キーコードごとにcase文に処理を書き、最後にイベント伝播をキャンセルしてbreak。

参考：[jQuery キーコード一覧表](http://musou.s38.xrea.com/jQuery/keycode.html)

# まとめ

- イベントの追加にはaddEventListnerを使う
- スクリプトをDOMに挿入して動かす
- Chromeでのキーコードの取得は[KeyboardEvent.which](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)を使う

それにしても、キーイベントを取得したい事なんて山程あるだろうに、未だ仕様が固まっていないってどういう事なんですかね…。