ブログ

Macの音声入力は入力先をどう見分けるのか:アプリと欄を読む仕組み

TalkTalkTypeは、フォーカス中のアプリと入力欄を決定論的な分類で読み取り、音声による推敲の段階で結果を適応させます。モード選択は不要です。

執筆 tsuvic公開 読了約7分

Mailで返信を半分まで書いたところで、⌥Spaceを押しっぱなしにして十秒ほど話し、手を離します。整えられた一文は、別のエディタでもクリップボードでもなく、メールの本文欄へ直接入ります。

どこへ入れるかを、あなたが指示した覚えはないはずです。

多くの音声入力は、行き先を逆の順番で扱います。話す前にモードを選ばせます。そのまま書き出すモード、句読点を整えるモード、プロンプト向け、チャット向け、メール向け、という具合です。行き先は利用者が宣言し、ツールはその宣言を信じる。TalkTalkTypeには、そうした選択UIがありません。行き先を自分で読みます。あなたがいたアプリと、カーソルがあった欄の両方を固定の対応表で分類し、あなた自身が起動する音声推敲の段階で結果を適応させます。

この記事では、その読み取りがどう動き、何を変え、どこで止まるのかを扱います。

入力先は、キーを押した瞬間に決まる

録音はキーを押した瞬間に始まります。その瞬間、Macアプリはフォーカス中のアプリを入力先として捕まえます。プロセスID、バンドルID、アプリのローカライズ名です。結果ができると、そのアプリへ文章を返します。

渡し方は二つあります。Pasteモードでは、macOSのAccessibility APIを使って、あなたがいた欄へ文章を挿入します。このときクリップボードをいったん保存し、貼り付け後に元へ戻します。Copyモードでは、結果をクリップボードに置いたまま、手動の貼り付けを待ちます。どちらでも、入力先はキーを押した瞬間に使っていたアプリであり、発話の前に確定しています。

キーを押した瞬間に捕まえる、という点が、全体を自動に感じさせている正体です。文章ができてから入力先を探していたら、あなたがウィンドウを切り替えたあとで、結果が別の場所へ飛んでしまいます。始めた欄で、そのまま終わる。この受け渡しの仕組みと、背景にあるmacOSの権限は、Macのどのアプリでも使える音声入力で詳しく扱っています。

分類は推測ではなく、固定の対応表

入力先のアプリが分かると、分類器は今いる場所がどんなサーフェスかを判定します。ここで言語モデルには問いません。

第一段階は、バンドルIDを固定のプレフィックス対応表でアプリの族へ割り当てます。Terminal、iTerm2、Warp、WezTerm、kittyはターミナル。VS Code、Xcode、JetBrains系、Sublime Text、Zedはコードエディタ。MailとOutlookはメール。Slack、Discord、LINE、Telegramはチャット。TextEdit、Notes、Pages、Word、Obsidianは文書。Safari、Chrome、Firefox、Arcはブラウザ、となります。

第二段階は、入力欄のAccessibilityのroleとsubroleでサーフェスを絞り込みます。検索欄(AXSearchField)は検索クエリ。Mailでは、テキストエリアがメール本文、テキストフィールドが件名になります。チャットアプリでは、テキストエリアかテキストフィールドがチャットメッセージ。文書アプリでは、テキストエリアが文書、テキストフィールドが短い入力欄。コードエディタでは、テキストエリアがコードエディタのサーフェスになります。

ここには推論がなく、対応表といくつかのrole判定があるだけです。その見返りとして、すべての分類には監査可能な理由文字列が付きます。Mailの本文は app_family:email role:AXTextArea subrole:- と分類されます。なぜその結論になったのかをそのまま読めます。結論が、モデルの確信度ではなく、目に見える二つの事実から導かれているからです。

対応表が外れたときは、安全な側へ倒れます。バンドルIDが未知のアプリは、理由 unknown_app でunknownに分類されます。既知のアプリでも、未知のroleの欄は同じくunknownで、理由は unknown_role です。unknownとは、何もしない、という意味です。これが安全な既定値です。欄が何かを判定できないとき、TalkTalkTypeは推測で外すのではなく、言葉をそのまま扱います。

サーフェスごとに何が変わるか

サーフェスの分類は、推敲の段階で何に適応してよいかを決めます。対応は次の通りです。

アプリと欄 検出されるサーフェス 変わること
MailまたはOutlook、本文のテキストエリア メール本文 メール本文として扱う
MailまたはOutlook、件名欄 メール件名 件名として扱う
Slack、Discord、LINE、Telegram チャットメッセージ チャットのメッセージとして扱う
VS Code、Xcode、JetBrains系、Sublime、Zed コードエディタ ファイル名、パス、スラッシュコマンドはテキストのまま保持し、実行しない
Terminal、iTerm2、Warp、WezTerm、kitty ターミナル コードエディタと同じ技術トークン扱い
TextEdit、Notes、Pages、Word、Obsidian、テキストエリア 文書 文書として扱う
TextEdit、Notes、Pages、Word、Obsidian、テキストフィールド 短い入力欄 一行の入力欄として扱う
既知アプリの検索欄 検索クエリ 検索クエリとして扱う
Safari、Chrome、Firefox、Arc unknown 適応しない。Webの欄は構造的に信頼できない
未知のアプリまたはrole unknown 適応しない(安全側の既定値)

二つの行には補足が要ります。ブラウザの行が常にunknownなのは、わざとです。Webページはどんな欄でも自由に描けます。ネイティブのMailやSlackの欄を読み取り可能にしている構造的な手がかりは、ブラウザのタブの中では成り立ちません。だからTalkTalkTypeは、Webの欄を分類したふりをせず、そのままにします。

コードエディタとターミナルの行には、技術トークンについての具体的な保証があります。これらのサーフェスでは、口にしたファイル名、パス、スラッシュコマンドは、ただのテキストとして保たれます。それが存在する、解決できる、実行される、といった扱いは一切されません。ターミナルへコマンドを音声入力しても、得られるのは文字列そのもので、それ以上ではありません。

適応は書き換えではなく、推敲の一段階

ここは最も大げさに言いやすい部分なので、境界が重要です。

整形後の結果は、まずメニューバーのHUDに下書きとして届きます。この最初の貼付は忠実なClean出力です。Cleanは、口にしたすべての言葉を、言った順序で、意図した丁寧さと簡潔さのまま保ちます。曖昧さのない言い淀みだけを除き、一行へまとめ、言い換え、補完、推敲をしません。Rawモードは整形を完全に省きます。最初に見えるのは、あなたが言ったものです。

文脈を読む適応は、その後のVoice Patchの流れで起きます。下書きから、挿入の前に音声で推敲を指示できます。あるいは、そのまま確定、コピー、破棄もできます。サーフェスへの適応を求めると、モデルへの指示は文字通り「渡された決定論的なデスクトップアプリと欄の分類にのみ適応せよ」です。同じ流れが、意味と保護された事実をすべて保ち、必要最小限の編集だけを行い、画面について受け取った情報をすべて、命令ではなくデータとして扱います。

つまり、Mailを見つけた瞬間に最初の下書きを「メール風」へこっそり書き換える、ということは起きません。忠実な下書きを見せ、そのうえで、検出したサーフェスに基づいて、あなたが音声で頼んだ適応が行われます。

では、なぜ他のツールはまだモードを選ばせるのか、という問いが残ります。TalkTalkTypeには、設定のどこにも出力モードの選択がありません。あるスイッチはCleanのオンとオフだけです。忠実な軽い整形か、何もしないか。行き先に固有の整え方は、すべて欄の読み取りから来ます。利用者が管理するモードからは来ません。強みとして見てほしいのはそこです。話す前に設定するものが一つ減り、間違えて設定するものがゼロになる、という点です。

コンテキストは同意の境界を越えるか、一切送られないか

欄を読むと、当然の疑問が浮かびます。画面の他の情報は、どうなるのか、と。

アプリが組み立てられるコンテキストのスナップショットには、アプリの識別情報、ウィンドウタイトル、欄の構造(role、subrole、複数行か、パスワード欄か)、カーソルの直前と直後のテキスト、現在の選択範囲、任意のアクティブウィンドウのスクリーンショット、取得時刻、権限の状態が含まれます。扱う範囲が広いので、境界はクライアントの善意ではなく、サーバー側で強制されます。

最も重要なのは二つです。第一に、欄のラベルとプレースホルダは、AIプロバイダーへ一切送られません。これらの文字列は他のアプリが供給する自由なテキストであり、分類には構造的な属性だけで足りるため、サーバーはラベルやプレースホルダを含むリクエストをその場で拒否します。第二に、各コンテキストの経路(テキストの文脈、スクリーンショット、設定の記憶)は、サーバーが所有するフィーチャーフラグの背後にあります。三つとも本番では既定でオンで、デプロイごとに上書きできます。ある経路がリクエストに対して有効でない場合、サーバーはコンテキストを黙って削るのではなく、拒否します。拒否されれば、クライアントは自分の同意状態が古いと分かります。黙って削れば、それは隠れてしまいます。

Mac、サービス、プロバイダーのそれぞれが何を保持するかというデータ台帳の全体は、Macのプライベート音声入力にあります。

設定はこのMacだけで覚える

コンテキストの最後の一片は、設定の記憶です。これはMacの中にとどまります。

設定は、ローカルのSQLiteデータベースに保存されます。場所は ~/Library/Application Support/TalkTalkType/PreferenceMemory/preferences.sqlite で、クラウド同期はありません。保存するキーは、意図的に絞られています。返信のトーン(簡潔、中立、フォーマル、親しみやすい)、Oxford commaを使うか、0から2までの詳細度、好みの用語の一覧です。各設定は、すべてのアプリか、バンドルIDで指定する一つのアプリに紐づきます。一つのアプリへの設定は、全体設定より優先されます。

ここにあるものは、明示的に承認され、かつ有効にされるまで、一切使われません。推敲のリクエストには、抽象化された値だけが乗ります。生の音声、下書きの文章、却下された候補は、この保存領域に書き込まれません。あるアプリで繰り返し修正すると、アプリが設定を提案することがあります。ただし、提案はあなたが承認するまで何もしません。

苦手なところ

誠実な限界は、設計の一部であり、脚注ではありません。

ブラウザはunknownに分類されるので、Webフォームへのサーフェス適応はありません。Webの欄の構造を信頼しないためです。適応は音声推敲の流れの中で行われ、最初の下書きの黙った書き換えとしては起きません。最初の下書きは、設計により忠実なままです。適応があなたの言葉を言い換えで消すこともありません。意味と保護された事実は保たれ、編集は指示を満たす最小のものに限られます。

対応はMacのみで、macOS 26(Tahoe)以降が必要です。文字起こしはクラウドで動くため、処理中に音声はMacの外へ出ます。サービスは、音声も文字起こしの文章も、既定では保存しません。認識する言語は日本語と英語です。「コピー」「Safariを開いて」といった音声コマンドは、同じ考え方の別の表れで、テキストとして打ち込まれる代わりに、捕まえたアプリに対するMacの操作として実行されます。

自分の仕事で試すなら

この設計が主張しているのは、入力先とは、アプリが読み取れる事実であって、あなたが管理し続ける設定ではない、ということです。モード選択はその仕事を利用者へ外注します。そして選択UIとは、あなたが切り替えを忘れた瞬間に、ツールが破ってよい約束のことです。バンドルIDと欄のroleに対する対応表は、もっと退屈で、もっと正直です。限られた数のアプリを正確に知り、分からないときは分からないと言います。

TalkTalkTypeは、利用量を単語ではなく、週あたりの音声入力件数と、週あたりの音声時間の枠で数えます。2026年7月30日時点で、プランはFreeが0ドル(週30件、15分)、Plusが1ドル(週80件、30分)、Proが7ドル(週500件、250分、1回2分まで)、Maxが18ドル(週1,200件、600分)です。現在の数値とプランの提供状況は料金ページにあります。

TalkTalkTypeをダウンロードして、あなたが実際に使う欄で検出を試せます。Mailで、ターミナルで、ブラウザのフォームで、それぞれホットキーを押し、結果がどこへ届き、何に触らないままにするかを見てください。アプリは、あなたがどこで入力しているかをすでに知っています。興味深いのは、それを知らないとき、どれほど率直にそう告げるかです。

ブログ