コルタナさん、とても便利なのですが Vim を起動する事が出来ない。どこかで見たショートカットファイルを所定の場所に置く方法もうまく動かない。
C:\ProgramData\Microsoft\Windows\Start Menu\Programs
調べると、ボイスコマンドという API が出ているのだけど、Universal Application でないといけない。Universal Application だと System.Diagnostic からプロセスを起動できない。そこで別に立てたウェブサーバから Vim を起動させる。サーバのコードは至って簡単。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Server
{
class Program
{
static void Main(string[] args)
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8888/");
listener.Start();
while (true)
{
HttpListenerContext context = listener.GetContext();
HttpListenerRequest req = context.Request;
HttpListenerResponse res = context.Response;
if (req.RawUrl == "/vim")
{
Process.Start("gvim");
res.StatusCode = 200;
}
else
{
res.StatusCode = 404;
}
res.Close();
}
}
}
}
次に空の Universal Application を作り、OnLaunched イベントでボイスコマンドAPIにコマンド定義を食わせる。
protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
// ウィンドウに既にコンテンツが表示されている場合は、アプリケーションの初期化を繰り返さずに、
// ウィンドウがアクティブであることだけを確認してください
if (rootFrame == null)
{
// ナビゲーション コンテキストとして動作するフレームを作成し、最初のページに移動します
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: 以前中断したアプリケーションから状態を読み込みます
}
// フレームを現在のウィンドウに配置します
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// ナビゲーション スタックが復元されない場合は、最初のページに移動します。
// このとき、必要な情報をナビゲーション パラメーターとして渡して、新しいページを
//構成します
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// 現在のウィンドウがアクティブであることを確認します
Window.Current.Activate();
try
{
// 俺コマンドの登録
StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(@"MyCommands.xml");
await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("ボイスコマンドの定義でエラーが発生しました", ex);
}
}
}
食わせるコマンド定義は XML で記述し、以下のようにした。
xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
<CommandSet xml:lang="ja-jp" Name="HayCortanaLaunchVim">
<CommandPrefix>ねぇ
<Example>ビムを起動して
<Command Name="OpenVim">
<Example>ビムを起動して
<ListenFor>ビムを起動して[下さい]
<Feedback>ビムを起動しています
<Navigate/>
これで「コルタナさん、ねぇ Vim を起動して」と喋るだけで http://localhost:8888/vim
にリクエストが飛び、サーバを経由して Vim が起動する。
サーバ起動しておかないといけないのが面倒臭い。ちなみにちゃんと作るならクライアントサーバ間でトークンか何かをやりとりする必要があるし、サーバも localhost からのアクセスに絞るべきです。
ソースは GitHub に置いておきます。