CakePHP5入門【コラム⑬】faviconと音声入力

A子
ちなみに、解像度は256×256ドットね


C菜

B美

A子


C菜
ブラウザを強制更新([Ctrl]+[F5])すると~


A子
あ、あとさー
スマホでチャットするときってフリック入力してるんだけど、これって声で入力することはできないかな?

B美
PHP言語じゃなくて、JavaScriptのコードになるけど…

A子
んじゃ、ぜひやろう!
(いちいち入力するのが面倒くさいんだもん…(苦笑))

B美
一つは「マイクが存在するかのチェック関数」で、もう一つは「マイク(音声)入力を処理する関数」ね

C菜
一つ目の「マイクが存在するかのチェック関数」はいつ実行するのでしょうか~?

B美
チャットページがロードされた際(画面表示されたとき)に実行されるよう、「DOMContentLoaded」イベントに追加すれば良いのよ

A子

B美
まずは「マイクが存在するかのチェック関数」だけど…
function checkMicrophone() {
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { document.getElementById('mic-status').textContent = "(音声入力チェックはサポートされていません)"; return; } navigator.mediaDevices.enumerateDevices() .then(function(devices) { const hasMicrophone = devices.some(device => device.kind === 'audioinput'); if (hasMicrophone) { //マイクがある場合、ボタンを表示 document.getElementById('start-recognition-btn').style.display = 'inline'; } else { document.getElementById('mic-status').textContent = "(マイクが見つかりませんでした)"; } }) .catch(function(err) { document.getElementById('mic-status').textContent = "(エラーが発生しました)"; }); } |
あ、上記コードを見れば分かると思うけど、HTML要素として「id」が「mic-status」であるタグ(pタグまたはdivタグ)と、「id」が「start-recognition-btn」であるボタンが必要だからね


C菜
<div style="padding: 10px;">
<div id="mic-status"></div> <button id="start-recognition-btn" class="button is-link">音声入力開始</button> </div> |
という感じで、いかがでしょう~?


B美
ボタンの初期状態は「非表示」にしておいてね
それとボタンの「onclick」イベントに(このあと記述する)「startRecognition」関数を割り当てておいてちょうだい

C菜
<div style="padding: 10px;">
<div id="mic-status"></div> <button id="start-recognition-btn" onclick="startRecognition()" style="display: none;" class="button is-link">音声入力開始</button> </div> |
で、どうでしょうか~?


B美
それじゃ、チャットページが表示されたタイミングで、この関数(マイクが存在するかのチェック関数)が実行されるようにしましょう
てか、すでに存在する「DOMContentLoaded」イベントの最後に一行追加するだけなんだけどね
document.addEventListener("DOMContentLoaded", function () {
const messageInput = document.getElementById("message"); const sendButton = document.getElementById("sendBtn"); //Enterキーで送信(Shift + Enterで改行) messageInput.addEventListener("keydown", function (event) { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); sendButton.click(); } }); checkMicrophone(); }); |


C菜

B美
「navigator.mediaDevices」という機能って、HTTPプロトコルのもとでは実行できないから注意してね
(これってマイクなどのデバイスリストを取得する機能なんだけど、「HTTPSの環境下じゃないと動作しない」決まりだから…)
なお、HTTPアクセスの場合は「(音声入力チェックはサポートされていません)」って表示されるようにしているわ
(下記はHTTPS環境なので、「(マイクが見つかりませんでした)」を表示 ← マイクの無いデスクトップPCなので…)


A子

B美
あと、入力欄のカーソル位置に挿入するための関数「insertTextAtCursor」を別に作成しておきましょう
(その関数を「startRecognition」関数の中から呼び出している…ってこと)
function startRecognition() {
if (!('webkitSpeechRecognition' in window)) { document.getElementById('mic-status').textContent = "(音声入力はサポートされていません)"; return; } const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const recognition = new SpeechRecognition(); recognition.lang = 'ja-JP'; //日本語を指定 recognition.interimResults = false; //暫定結果を無効 recognition.maxAlternatives = 1; //最大の候補数を設定 recognition.onstart = function() { document.getElementById('start-recognition-btn').style.display = 'none'; document.getElementById('mic-status').textContent = "(音声入力中)"; }; recognition.onresult = function(event) { const speechResult = event.results[0][0].transcript; insertTextAtCursor(speechResult); }; recognition.onerror = function(event) { document.getElementById('mic-status').textContent = "(エラー: " + event.error + ")"; }; recognition.onend = function() { document.getElementById('start-recognition-btn').style.display = 'inline'; document.getElementById('mic-status').textContent = ""; }; recognition.start(); } function insertTextAtCursor(text) { const inputField = document.getElementById('message'); const startPos = inputField.selectionStart; const endPos = inputField.selectionEnd; const currentValue = inputField.value; inputField.value = currentValue.substring(0, startPos) + text + currentValue.substring(endPos); inputField.selectionStart = inputField.selectionEnd = startPos + text.length; inputField.focus(); } |



A子

B美
強引に二つにしても良かったんだけど、「insertTextAtCursor」関数を独立させたほうが分かりやすいでしょ?

C菜

B美
マイク内蔵のノートPCからアクセスしてみるわね


A子

B美
(常に出るわけじゃなく、表示されるのは最初の一回だけだから安心してね)


C菜

A子


C菜
すぐに入力欄に埋め込まれましたよ~
(ほとんどタイムラグが無いですねぇ~)

A子
(「音声入力開始」ボタンをクリックして)「こんばんは」


C菜

A子
(「音声入力開始」ボタンをクリックして)「こんにちは」


C菜
きちんと間(カーソル位置)に挿入されました~

A子
次は、漢字変換がうまくいくかを試してみよう
(「音声入力開始」ボタンをクリックして)「これはおんせいにゅうりょくてすとです」


C菜
なにげに頭が良い感じがします~

B美
あ、ただし…
(日本語変換が割とうまく働くのは確かなんだけど)同音異義語はちょっと難しいかも…
例えば、「せんとう」が「先頭」「戦闘」「銭湯」「尖塔」等のどれかに変換されたとしても、それが自分の思ってるものとは違うかもしれないわ

A子
(自分で入力欄を修正できるように…)
まぁ、それでもめっちゃ楽なのは確かだけどね

B美
Androidスマホで使えるのは確認済みなんだけど、iPhoneで使えるかどうかは検証できていないわ
(だって持ってないんだもの)

A子