2016年4月10日日曜日

Cortanaをコマンドラインから呼び出す

※素人のメモ書きですのでご注意願います。

--
(2016/10/27追記)
どのタイミングからか不明ですが、build 14393時点でCortanaの呼び出しショートカットが「WINキー+SHIFT+c」に変更になってました。コードのみ修正しました。


--

win10搭載のCortanaに関して、「コルタナさん」と口で言うのは格好良くない気がしたので別の方法で呼び出すことにした。

最初はwin10の資料を探せばCortanaを呼び出すAPIくらいすぐ出るだろうと踏んだが、英語資料が読めず断念。

ブラウザから呼び出せるschemeがあるということは公式サイト内の「コルタナを起動する」リンクから見つけられたが、入力後すぐに音声待ち状態にはならなかったので不採用。
(ちなみにschemeは ms-cortana://)

色々調べた結果、「WINキー+c」「WINキー+SHIFT+c」 のショートカットでCortanaが呼び出せることが分かったのでキー入力を送るプログラムを書くことにした。


--

まず思いついたのは、VBScriptの利用。メモ帳で書いて拡張子を「.vbs」にすれば完成するので手軽。詳しくはないけれど、SendKeysの使い方も入力キーを書いてやるだけだったので。

set obj =CreateObject("WScript.shell")
obj.SendKeys "^{ESC}"


winキーの指定方法がMSDNになかったけれど、「WINキーはCtrl+ESCで代用可能」とあったのでこのように書いた。しかし、これではうまくいかない。どうやら「Ctrl+ESC」の組み合わせは「WINキー」ではなく「スタートメニューを表示する」だけの組み合わせのようだった。
結局SendKeysでWINキーの指定方法が見つけられなかったので、この方法は諦めた。

--

次にSendInput(参考:MSDN)を使用する案が出てきたので、ほとんど書いたことがないC++で挑戦。普段はC言語かつemacsでコード書いてcygwin+gccなので、Visual Studioの使い方から分からないという事態に。

「プロジェクトを新規作成」から「Visual C++ - Win32コンソールアプリケーション」で作成。コードはこちらを参考にさせてもらいつつ作成。





(おそらく初歩的なミスなのだろうが、includeの順をwindows.h,stdafx.hにしていたせいで「No target architecture」が出て大変だった)

LPINPUT構造体に関してまともに情報を見つけられなかったのが悔しい。こういうのは定義を見にいけば良いのだろうか。

見た範囲だと
  • type - キーボード入力ならINPUT_KEYBOARD,マウス入力ならINPUT_MOUSEになる
  • ki - (おそらく)Keyboard Inputの略,マウス入力を作るならmiになるっぽい
  • wVK - WORD型(16bits?)でのキーコード指定、0~255までで指定できる(参考)
  • wScan - 不明
  • dwFlags - 0だとキーを押すイベント、KEYEVENTF_KEYUPだと指定キーを放すイベント
  • time - 不明
となりそう。


 SendInput自体は、
  • SendInput(回数,キーイベントの配列(LPINPUT),配列の大きさ)
なので分かりやすい。

とりあえず、
  1. lpkeyの値を変更してWINキー押下の情報を作る
  2. SendInputでWINキー押下するという情報を送る
  3. lpkeyの値を変更してCキー押下の情報を作る
  4. SendInputでC押下するという情報を送る
  5. lpkeyのdwFlagsのみ変更してCキー開放の情報を作る
  6. SendInputでC開放の情報を送る
  7. lpkeyの残りをWINキー用に書き換えてWINキー開放の情報を作る
  8.  SendInputで投げる
という手順で「WINキー+c」が完成。

後はこれをVisual Studioの上部にある「ローカルWindowsデバッガー」を押して走らせて、問題が無ければ、横の「Debug」を「Release」に変えて、もう一度「ローカルWindowsデバッガー」を押すとexeを作ってくれる。
作成場所は出力ウィンドウの「出力元」を見ればパスが出ているが、多分「ソリューションエクスプローラー」を右クリックして「エクスプローラでフォルダを開く」を選んだ方が早いと思う。

完成のexeを実行して問題が無ければ、後はコマンドプロンプトのパスが通るところに置くなり、aliasでパスを指定しておけば、コマンドラインからCortanaを呼び出せるようになる。

とりあえずcygwinのconfig.iniにcortanaというコマンド名でaliasを書いている。設定はしたが全く実用性はなさそう。


--

(C++の方法で出来たので試してはいないけれど、SendInputがどこかのdllで設定されているならrundll32.exeでコマンドプロンプトから直接実行できるのではという方法もあった。
仕組みが全く分からない上に情報がぼんやりしすぎてて博打感が怖い)



--
追記: Cortanaの音声受付に成功して、結果が返ってからアクティブがCygwinに返ってこないのが気になっている。気が向いたら直す。

0 件のコメント:

コメントを投稿