SwitchDictLangアプリで音声入力言語切り替えと同時に音声入力を開始してみる

音声入力言語を切り替えるアプリSwitchDictLangの記事(Macで音声入力の言語を切り替えられるアプリを作りました)にコメントで要望を頂いたので、早速やってみました。

頂いた要望

Thanks for great work for this app,I love it.
But the “National Flag” of Taiwan is just not the right one.

And now it needs to 2 steps to launch the “音声入力”function.
(1.Switch languages 2. Launch the function.)

Is it possible just combine 2 to 1. Thanks.

  1. 台湾の国旗が違う
  2. 音声入力の言語を切り替えると同時に音声入力を始める

国旗

国旗はすみません、ずぼらして、こんなふうにごまかしていました。

  • 台湾のアイコン:
  • 中国のアイコン:
さりげなく、背景にTWといれて台湾のことにしていたのです。

というのも、音声入力のシステム環境設定で中国語がこんなふうに3つにわかれているのです。

  • 中国語(中国)
  • 中国語(中華人民共和国香港特別行政区)
  • 中国語(台湾)

中国語に設定されているということを国旗で表して、方言?を背景に省力文字でデザインしました。

全ての国の国旗を用意するのが大変だったのもあるのですが、アメリカやカナダやスイスが複数の言語を設定できるので、国=言語にならないのです。

  • スペイン語(アメリカ合衆国)
  • 英語(アメリカ合衆国)
  • イタリア語(スイス)
  • フランス語(スイス)
  • フランス語(カナダ)
  • 英語(カナダ)

しかし、明らかに国旗なのに設定言語を表すことにしているのは、まずかったですね。国旗だと思っているのに、自国の国旗と違う国旗が表示されるのは気分が悪いと思います。

デザインはあまり得意ではないので、少し時間がかかると思いますが、画像を作りたいと思います。

言語切り替えと同時に音声入力

さて、本題ですが、言語を切り替えたと同時に音声入力を始めるようにアプリを修正してみました。

音声入力を始めるAPIがないので、どうやって実現するか少し考えたのですが、一番簡単な方法でやることにしました。それは、「アプリで人間の動作と同じことをする」、すなわち、音声入力を開始するキー入力をアプリで発生させるのです。これなら、きっと絶対できるでしょうし、簡単でしょう。

と思ってやりはじめたのですが、2つ問題がありました。

  1. キー入力を発生させる方法
  2. 音声入力開始のショートカットキーを取得する方法

■ キー入力を発生させる方法

キー入力の発生は、ネットで検索するとわりとすぐに解決しました。

CGEventRef pressFN = CGEventCreateKeyboardEvent(NULL, hotkeyCode, true)
CGEventRef releaseFN = CGEventCreateKeyboardEvent(NULL, hotkeyCode, false);
CGEventPost(kCGHIDEventTap, pressFN);
CGEventPost(kCGHIDEventTap, releaseFN);
CGEventPost(kCGHIDEventTap, pressFN);
CGEventPost(kCGHIDEventTap, releaseFN);

こんなかんじのコードでhotkeyCodeの部分に実際のキーコード(Fnキーなら63)を入れればキー入力を発生させて、音声入力を開始することができました。

■ 音声入力開始のショートカットキーを取得する方法

音声入力開始のショートカットキーはFnキーがデフォルトですが、システム環境設定でユーザーが変更できるようになっているので、Fnキー決め打ちだとイマイチです。そこで、割り当てられているキーを取得して、そのキーコードで前記のキー入力を発生させなければいけません。

しかし、これがとても大変で、どこで定義されているのかはっきりしません。自分でシステム環境設定を変更しながらシステムを監視していると、次のドメインでユーザデフォルトに設定が保存されているようです。

com.apple.speech.recognition.AppleSpeechRecognition.prefs

その中身には、こんなかんじ。

AppleSymbolicHotKeys =     {
    10 =         {
        enabled = 1;
        value =             {
            parameters =                 (
                                          65535,
                                          96,
                                          262144
                                          );
            type = standard;
        };
    };
    11 =         {
        enabled = 1;
        value =             {
            parameters =                 (
                                          65535,
                                          97,
                                          262144
                                          );
            type = standard;
        };
    };
    118 =         {
        enabled = 0;
        value =             {
            parameters =                 (
                                          65535,
                                          18,
                                          262144
                                          );

延々とこんな内容が続きます。意味不明ですね。

音声入力のショートカットを変更すると、この中で次の部分が変わることが分かりました。

164 =         {
    enabled = 1;
    value =             {
        parameters =                 (
                                      8388608,
                                      "-8388609"
                                      );
        type = modifier;
    };
};

parametersの中の値が変化するようです。何の数字かさらに意味不明ですが、固定の値のようでショートカットキーに対応しています。

そこで、8388608の時はFnキー、1048592の時は右Commandキーなどと全て調べてコーディングしました。

試しに動かしてみます。

「ポン!」

ばっちりです!

これは便利!

しかし、もしかすると、切り替えと同時に音声入力したくない場合もあるかもしれないので、環境設定で変更できるようにします。

できました!

すぐにでもAppleに申請する気満々で、リリース用の環境でテストしてみます。

「 … 」

音声入力が始まりません。

デバッグ実行しても、特に問題なくコードは実行されています。

「なぜ!??」

リリース用の環境と開発用の環境で違うのは、Sandboxです。リリース用の環境はSandboxがオンになっています。

きっとこれです。

ネットで検索してみると見つかりました。

Stackoverflow:Can Mac App Store Sandboxed apps use CGEventPost?

「がーん」

なんと、CGEventPostを使ったアプリはMac Apple Storeに申請できないのです。

確かに、キー入力を発生させることができたらセキュリティ上問題がありそうです。

「しかし、しかし、悪いことをしようとしているわけではないのです!」

「これでアプリがとっても便利になるんです!」

「数時間かけてAPIにもない部分をがんばって実装したんです!(こそくな方法ですが)」

そんなことを思いましたが、どうしようもありません。残念です。。。


関連記事