使い方
https://xiaomuc.github.io/speech/
iPadもしくはiPhoneでこのページを開き、マイクボタンで押して音声入力すると、入力内容がテキストエリアに表示されるってだけです。
自動で消えます
どうせ残しておく必要のない情報を前提としているので、自動で消す機能がついております。iPad/iPhoneの音声入力は
- 無音状態が1分ぐらい続いたとき
- 手動でマイクボタン押したとき
に音声入力モードが終了します。音声入力モード終了後30秒で入力内容を消去します。
文字サイズと削除タイマ
文字サイズと音声入力後に入力内容を消すタイマ値を変えられます。
たとえば文字サイズ48pt、タイマを5秒(5000ミリ秒)にしたい場合は:
https://xiaomuc.github.io/speech/?size=48pt&timer=5000
って感じにしてください。
なお、デフォルトは文字サイズ36pt、タイマ30秒です。
参考にさせていただいた記事
コード
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="style.css" />
<body>
<form id="text_form">
<div class="FlexTextarea">
<div class="FlexTextarea__dummy" aria-hidden="true"></div>
<textarea id="FlexTextarea" class="FlexTextarea__textarea" ></textarea>
</div>
</form>
<!--div id="debug" class="debug">
<textarea id="event-log" rows="10" cols="50"></textarea>
<textarea id="list-view" rows="10" cols="50"></textarea>
</div-->
<script src="speech.js"></script>
</body>
</html>
.FlexTextarea {
font-size: 36pt;
position: relative;
line-height: 1.8;
}
.FlexTextarea__dummy {
overflow: hidden;
visibility: hidden;
box-sizing: border-box;
padding: 5px 15px;
min-height: 120px;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
border: 1px solid;
}
.FlexTextarea__textarea {
position: absolute;
top: 0;
left: 0;
display: block;
overflow: hidden;
box-sizing: border-box;
padding: 5px 15px;
width: 100%;
height: 100%;
background-color: transparent;
border: 1px solid #b6c3c6;
border-radius: 4px;
color: inherit;
font: inherit;
letter-spacing: inherit;
resize: none;
}
.FlexTextarea__textarea:focus {
box-shadow: 0 0 0 4px rgba(35, 167, 195, 0.3);
outline: 0;
}
// get url params
var url = new URL(window.location.href);
var params = url.searchParams;
const inputTextarea = document.getElementById('FlexTextarea');
var timer;
var inputArray = [];
// set flexible textarae and initialize font size, timer setting
function flexTextarea(el) {
// Font size
sz = params.get('size');
if (sz != null) {
el.style.fontSize = sz;
}
// Timer msec
tm = params.get('timer');
if (tm == null) {
tm = 30000;
}
// initialize
const dummy = el.querySelector('.FlexTextarea__dummy');
el.querySelector('.FlexTextarea__textarea').addEventListener('input', (e) => {
dummy.textContent = e.target.value + '\u200b';
inputTime = performance.now();
inputValue = e.data;
if (inputValue == null) {
inputValue = '[null]';
}
if (inputArray.length > 0 && inputTime - inputArray[0].time < 5) {
inputValue = inputArray[0].value + inputValue;
}
inputArray.unshift({
time: inputTime,
value: inputValue
});
clearTimeout(timer);
for (var i = 0; i < inputArray.length; i++) {
var item = inputArray[i];
if (inputTime - item.time > 5 && inputValue == item.value) {
timer = setTimeout(clr, tm);
break;
}
}
});
}
// clear textarea
var clr = function() {
document.getElementById('text_form').reset();
inputTextarea.focus();
inputArray = [];
};
// initialize when windows has loaded
window.onload = function() {
document.querySelectorAll('.FlexTextarea').forEach(flexTextarea);
};
音声入力の終了を判定する
この辺がちょっと工夫が必要だったので。
音声入力がされると、TextAreaのinputイベントが飛んできます。
音声入力が終了したときにもまったく同じ内容のinputイベントが飛んでくるんで、
入力内容を保持しておいて全く同じだったらタイマスタート、タイムアウト時にテキストエリアの中身を消しています。
困ったのは改行が入ったときです。音声入力時に「かいぎょう」って言うと
改行コード入れてくれるので表示状は見やすくなるんですが、
inputイベントとしてはdata値がnullで飛んできちゃうし、
音声入力終了時に入力文字列と改行が個別のイベントとして発生するんですな。
ただ、別々のイベントながらほぼ同時に発生するので、
10msec以内に発生したinputイベントを同一入力とみなすことでこの辺を解決しています。
なんのために?
こんなモノ作ったかというと、年取って耳が遠くなった母親とのコミュニケーションのためです。
ここ数年で急激に耳が悪くなり、ほとんど聞こえていないようなんです。
最初は耳元で大声出してたんですが、それでも聞き取れず会話に参加できなくなってきてました。
運良く数年前に買ったiPadがあるので、メモアプリ立ち上げて音声入力してみたところ
割と認識率もよくスピードも早いので行けそうだってなりました。
ただ、大した会話でもないのにメモアプリは情報が残ってしまうんですよね。
文字がたくさん並ぶとそれはそれで見にくいし、いちいち消したり、
新しいメモページ作ったりって操作自体もハードルが高い。
なら時間が立ったら勝手に消えちゃえばいいんじゃないかと。
また会話開始するのにはマイクボタン押せばいいので操作がシンプルになりました。
小さい字も見えないので字もでかく設定しています。