#10　【Chrome用】Google Chatの改行設定を変更してみた

## 追記

閲覧数が多かったのでchromeウェブストアに公開しました。
こちらのURLより適用してください。
https://chrome.google.com/webstore/detail/google-chat-%E6%94%B9%E8%A1%8C%E3%82%AD%E3%83%BC%E8%A8%AD%E5%AE%9A/mfnigpcpfllpnmaobnojkhbhkefnemhk
インストール後、拡張機能のポップアップ(chromeのアドレスバーの横にあるパズルのピースの形のボタン)から改行設定をしてください。

ここから下は、開発時の内容です。仕組みが知りたい方はどうぞ↓

## 概要

Google Chat のデフォルトは、`Enter`で投稿、`Shift + Enter` で改行です。
今回作成した拡張機能を読み込ませることで、 `Enter` で改行、`Shift`, `Ctrl`, `Alt` のどれか + `Enter` で投稿になります。

Google Chat のWindowsアプリ または Google Chrome で適用できます。

## 経緯

普段使っている他のチャットツールはいずれも `Enter` が改行なので、Google Chat のコマンドになかなか慣れませんでした。
ググっても変更方法が見つからないため諦めかけてたのですが、Chrome の拡張機能としてコマンドを上書きすれば可能かもしれないと思いついたので実践してみました。

## 使い方

以下のファイルを1つのフォルダに配置し、パッケージ化されていない拡張機能として読み込ませることで適用されます。(参考: https://support.google.com/chrome/a/answer/2714278?hl=ja)
サンプルでは `Shift + Enter` で投稿する設定としていますが、`custom_line_break.js` の3行目を変更することで、`Ctrl + Enter` や `Alt + Enter` にすることも可能です。

```json:manifest.json
{
  "name": "Google Chat 改行キーカスタム",
  "description": "Enterで改行、Shift or Ctrl or Alt + Enterで投稿。■確認環境 ブラウザ:Google Chrome 112.0.5615.138 端末:Windows11",
  "version": "1.0.0",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["*://chat.google.com/*"],
      "js": ["custom_line_break.js"],
      "all_frames": true
    }
  ]
}
```

```javascript:custom_line_break.js
// 投稿キー設定: 何キー + Enter の同時押しで投稿するか
// shiftKey | ctrlKey | altKey
const POST_KEY = "shiftKey";

window.addEventListener("keydown", handler, true);

function handler(event) {
  if (event.key !== "Enter") {
    // Enterキー以外は何もしない
    return;
  }
  if (event.isModified) {
    // 無限ループ防止
    return;
  }

  if (event[POST_KEY]) {
    // 投稿キー + Enter の場合
    // Enter 単体イベントを発火させて投稿を実行
    const properties = [];
    for (const key in event) {
      properties[key] = event[key];
    }
    properties.shiftKey = false;
    const modifiedEvent = new KeyboardEvent("keydown", properties);
    modifiedEvent.isModified = true;
    event.target.dispatchEvent(modifiedEvent);
  } else {
    // Enter 単体の場合
    // 改行実行
    document.execCommand("insertLineBreak");
  }

  // デフォルトの動作を抑止
  event.preventDefault();
  event.stopImmediatePropagation();
}
```

## 躓いたポイント

### javascriptが適用されない
manifest.json の設定が誤っていました。
Google Chat のURLは `https://mail.google.com/chat/~` なので、最初はmanifest.json の matches を`*://mail.google.com/chat/*`にしていたのですが、どうやらチャットの入力欄はiframeになっているためそこまでスクリプトが届いていなかった模様。
iframe内部のURLである `*://chat.google.com/*`を指定し、`"all_frames": true`の設定を追加したところ適用されるようになりました。

### event.shiftKey が書き換えできない
初めは、イベントをキャッチして、`event.shiftKey`の値を反転させるだけで動作するんじゃないかと思っていたのですが、`event.shiftKey`は読み取り専用プロパティのため上書きできませんでした。。。
そのため、方針を変更して、最初にキャッチしたイベントは抑止して、`shiftKey`を反転させた新たなイベントを発火させる方針としました。

### デフォルトの動作が抑止できない
改行を止めるのは、`event.preventDefault()` ですんなりできたのですが、投稿がなかなか抑止できなかったです。
`window.addEventListener` の第三引数を`true`にすることでイベントキャッチのタイミングを早めて、`event.stopImmediatePropagation()`を実行することで抑止できました。

### 改行イベントを起こせない
これが一番苦労しました。
`Shift + Enter` のイベントを発火させても改行が実行されませんでした。
実際の入力時と同じ流れになるように、
`Shift`の`keydown`→`Shift`の`keypress`→`Shift+Enter`の`keydown`→`Shift+Enter`の`keypress`
の順で発火してもダメでした。
どうやら、Google Chatの入力欄では`contenteditable="true"`により`div`を編集可能にしているようで、改行はJavaScriptのイベントハンドラではなくブラウザによって実行されている様子。
私の場合は、`contenteditable`属性の存在を知らず、Google自作のカスタム属性の一つだと思っていたので気づくのに時間がかかりました。
最終的に、`document.execCommand("insertLineBreak");`という関数を実行することで解決しました。

## 今後の課題

* 改行キーの設定をコードからでなくUIでできるように
* `document.execCommand()`が`deprecated`なので置き換え

以上です、ありがとうございました！