JavaScript
ブックマークレット

KuroTwiで音声入力ツイートを行うブックマークレット(454バイト)

使い方

ブックマークレット
javascript:(()=>{let g=x=>$('#'+x)[0],i='voiceInput',h='innerHTML',r=new webkitSpeechRecognition(),a=document.createElement`a`;a.className='btn tooltip';a.id=i;a.tooltip='音声入力';a[h]='●';a.onclick=t=>{t.target[h]='=';r.start()};r.addEventListener('result',e=>{g`tweetbox_text`.value+=e.results[0][0].transcript+'\n';$._data($('#tweetbox_text')[0],'events').keyup[0].handler();g(i)[h]='●'},!1);g(i)?0:g`tweetbox_btn`.insertBefore(a,g`eventbtn`);})()

上のコードをブックマークレットとして登録します。
そのブックマークレットをKuroTwiでクリックします。
「ツイート」パネルの下書きボタンの左側に「●」ボタンが出てきます。
「●」ボタンをクリックすると「=」になり、音声入力に入ります。
そこで適当に喋ると、テキストが入力されます。
ツイートパネルに追加されたボタン

コード説明

中身

音声入力

音声入力のテスト.js
let recognition = new webkitSpeechRecognition();
recognition.lang = 'ja';

recognition.addEventListener('result', function (event) {
    let text = event.results.item(0).item(0).transcript;
    console.log(text);
}, false);
recognition.start();

F12を押して開発者ツールを開き、上のコードをConsoleに貼り付けてEnterを押して下さい。
マイクの使用許可が求められるので、許可をして何かを話すとコンソールに入力されます。
(参考サイト:1)

KuroTwiにボタンを追加する

KuroTwiのツイートボタン周りのソース

ツイートボタン周りは、tweetbox_btnというIDの要素に格納されています。
この要素の中の先頭に音声入力ボタンを追加します。
まず、tweetbox_btnの子要素の先頭にはバルスボタンがついているので、これの前に音声入力ボタンを持っていきます。

let a = document.createElement('a');
a.className = 'btn tooltip';
a.id = 'voiceInput';
a.tooltip = '音声入力';
a.innerHTML = '●';
a.onclick = function(t){
    t.target.innerHTML = '=';
    recognition.start();
};
document.getElementById('tweetbox_btn').insertBefore(a, document.getElementById('eventbtn'));

何回も押すと無限に音声入力ボタンが生成されてしまうので、以下のコードのようにボタンがすでに生成されたかを確認してそうならないようにします。

if (!document.getElementById('voiceInput')) {
    /* any */
}

録音終了時の処理

録音終了時の処理.js
function (event) {
    let text = event.results.item(0).item(0).transcript;
    console.log(text);
}

「音声入力のテスト.js」の一部を抜き出しました。
変数textには音声入力で認識された文字列が格納されています。
これをテキストエリア(ID:tweetbox_text)に追記するようにします。
また、音声入力ボタンの表示も「●」に戻しておきます。

function (event) {
    let text = event.results.item(0).item(0).transcript;
    document.getElementById('tweetbox_text').value += text + '\n';
    document.getElementById('voiceInput').innerHTML = '●';
}

これでも動きますが、残り文字数が更新されなかったり、ツイートボタンが有効にならなかったりします。
そこで、テキストエリアにキーボードで文字が入力された際に実行される関数を流用できないかと考えます。
「tweetbox_text」でソースを検索すると、以下のような関数が見つかりました。
テキストエリア更新の際に実行される関数
この関数は、テキストエリアの文字数を確認し、残り文字数の更新とツイートボタンの有効/無効の切り替えをしています。
この関数を流用します。
しかし、素のJavaScriptではどうにもならなかったため、おとなしくjQueryを使用しました(参考サイト:2)。
「録音終了時の処理.js」は以下のようになりました。

function (event) {
    let text = event.results.item(0).item(0).transcript;
    document.getElementById('tweetbox_text').value += text + '\n';
    $._data($('#tweetbox_text').get(0), 'events').keyup[0].handler();
    document.getElementById('voiceInput').innerHTML = '●';
}

すべてくっつける

上のものをくっつけると以下のようになります。

くっつけたコード.js
    let recognition = new webkitSpeechRecognition();
    recognition.lang = 'ja';

    recognition.addEventListener('result', function (event) {
        let text = event.results.item(0).item(0).transcript;
        document.getElementById('tweetbox_text').value += text + '\n';
        $._data($('#tweetbox_text').get(0), 'events').keyup[0].handler();
        document.getElementById('voiceInput').innerHTML = '●';
    }, false);

    if (!document.getElementById('voiceInput')) {
        let a = document.createElement('a');
        a.className = 'btn tooltip';
        a.id = 'voiceInput';
        a.tooltip = '音声入力';
        a.innerHTML = '●';
        a.onclick = (t) => {
            t.target.innerHTML = '=';
            recognition.start();
        };
        document.getElementById('tweetbox_btn').insertBefore(a, document.getElementById('eventbtn'));
    }

ショートコーディング

「くっつけたコード.js」を頑張って短くすると以下のようになります(参考サイト:3、4、5)。
recognition.lang = 'ja';はあってもなくても変わらないため、省略しました。

短くしたコード.js
(()=>{let g=x=>$('#'+x)[0],i='voiceInput',h='innerHTML',r=new webkitSpeechRecognition(),a=document.createElement`a`;a.className='btn tooltip';a.id=i;a.tooltip='音声入力';a[h]='●';a.onclick=t=>{t.target[h]='=';r.start()};r.addEventListener('result',e=>{g`tweetbox_text`.value+=e.results[0][0].transcript+'\n';$._data($('#tweetbox_text')[0],'events').keyup[0].handler();g(i)[h]='●'},!1);g(i)?0:g`tweetbox_btn`.insertBefore(a,g`eventbtn`);})()

要素の生成はjQueryでもう少し頑張れそうでしたが、諦めました。jQueryを使えばもっと短くできると思います。

バージョン

Chromeのみ動作を確認しています。
Chrome: 63
KuroTwi: 1.9.2.2

参考サイトさん

  1. ブラウザからの音声入力を認識してテキスト化する (Web Speech API)
  2. Check! jQuery ですでに登録されているイベントを取得し、割込ませたりするメモ
  3. jQueryでdocument.getElementByIdと等価を取る : mwSoft blog
  4. タグ名を指定してノードへアクセス - DOM入門 - JavaScript入門
  5. JavaScript ショートコードテクニック集(ES6含む)