この記事では、Microsoft Copilot ハードウェア キーまたは Windows キー + C が押されたとき、長押しされたとき、またはリリースされたときに、アプリを登録して通知を受け取る方法について説明します。 この機能を使用すると、アプリは、検出されるキー状態の変化に応じて異なるアクションを実行できます。 たとえば、アプリは、キーが 1 回押されたときに通常のアクティブ化を実行するが、キーが押されて保持されているときにスクリーンショットを撮る場合があります。 または、アプリでオーディオの記録を開始し、キーが押されて保持されているときにオーディオが記録されていることを示す状態インジケーターを表示し、キーが解放されたときにオーディオの録音を停止する場合があります。 キーを押し、保持状態に移行するには、少なくとも 300 ミリ秒保持する必要があります。
この機能は、基本的なMicrosoft Copilotハードウェア キー プロバイダーの機能を拡張します。この機能は、ハードウェア キーが押されたときに起動されるように登録するだけです。 詳細については、「Microsoft Copilot ハードウェア キー プロバイダーを参照してください。
この記事の残りの部分では、1 回押すか、Microsoft Copilot ボタンを長押しして離すことで開始されたアクティブ化に応答する単純な C# WinUI 3 アプリの作成について説明します。
新しいprojectを作成する
Visual Studioで、新しいprojectを作成します。 この例では、新しいプロジェクト ダイアログで、言語フィルターを C# に設定し、プロジェクトの種類を WinUI に設定し、「空のアプリ、パッケージ (デスクトップ内の WinUI)」を選択します。
Microsoft Copilot キーが押された状態を追跡するプロパティを追加する
この例では、現在のアクティブ化状態を UI に表示するために使用する State というプロパティを作成します。
MainWindow.xaml.csでは、MainWindow の定義内に次のコードを追加して、XAML ファイルにバインドできる文字列プロパティを作成します。
// MainWindow.xaml.cs
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "State")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void SetState(string state)
{
State = state;
}
private string _state;
public string State
{
get => _state;
set
{
if (_state != value)
{
_state = value;
OnPropertyChanged();
}
}
}
TextBox コントロールを UI に追加して、アプリの現在のアクティブ化状態を表示します。 MainPage.xaml の既定の StackPanel 要素を次のコードに置き換えます。
<!-- MainWindow.xaml -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Name="KeyStateText" Text="{x:Bind State, Mode=OneWay}" />
</StackPanel>
最後に、ウィンドウの作成時に State プロパティを設定する引数を受け取るように MainWindow コンストラクターを更新します。
// MainWindow.xaml.cs
public MainWindow(string state)
{
this.InitializeComponent();
_state = state;
}
URI アクティブ化に登録する
システムは、URI アクティベーションを使用して Microsoft Copilot のハードウェア キー プロバイダーを起動します。 uap:Protocol 要素をアプリ マニフェストに追加して、起動プロトコルを登録します。 URI スキームの既定のハンドラーとして登録する方法の詳細については、「 URI アクティブ化の処理」を参照してください。
次の例は、URI スキーム "myapp-copilothotkey" を登録する uap:Extension を示しています。
<!-- Package.appxmanifest -->
...
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
...
<Extensions>
...
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="myapp-copilothotkey"> <!-- app-defined protocol name -->
<uap:DisplayName>SDK Sample URI Scheme</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
...
Microsoft Copilot ハードウェア キー アプリ拡張機能
Microsoft Copilotハードウェア キー プロバイダーとして登録するには、アプリをパッケージ化する必要があります。 アプリのパッケージ化の詳細については、「
uap3:AppExtension 要素内に、子要素 PressAndHoldStart と PressAndHoldStop を含む uap3:Properties 要素を追加します。 これらの要素の内容は、前の手順でマニフェストに登録されたプロトコル スキームの URI である必要があります。 クエリ文字列引数は、ユーザーがホット キーを押して保持したため、またはユーザーがホット キーを解放したために URI を起動するかどうかを指定します。 アプリは、アプリのアクティブ化中にこれらのクエリ文字列値を使用して、実行する正しいアクションを決定します。 SingleTap 要素の指定は省略可能ですが、アプリが Copilot ハードウェア キーから起動されたかどうかを判断するのに役立ちます。
<!-- Package.appxmanifest -->
<Extensions>
...
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.copilotkeyprovider"
Id="MyAppId"
DisplayName="App display name"
Description="App description"
PublicFolder="Public">
<uap3:Properties>
<SingleTap>myapp-copilothotkey://?state=Tap</SingleTap>
<PressAndHoldStart>myapp-copilothotkey://?state=Down</PressAndHoldStart>
<PressAndHoldStop>myapp-copilothotkey:?//state=Up</PressAndHoldStop>
</uap3:Properties>
</ uap3:AppExtension>
</uap3:Extension>
...
URI のアクティブ化を処理する
アプリが URI のアクティブ化によってアクティブ化されたかどうかを検出するには、 AppInstance.GetActivatedEventArgs を呼び出し、 AppActivationArguments.Kind プロパティの値が Protocol であるかどうかを確認します。 アプリがプロトコルのアクティブ化によって起動された場合は、URI スキームがアプリ マニフェストで指定したプロトコル名と同じかどうかを確認します。 これらのテストがすべて成功した場合、Copilot ハードウェア キーを押したユーザーによってアプリがアクティブ化されたことがわかります。 この時点で、URI クエリ文字列を解析し、状態パラメーターを取得できます。 この パラメーターには、アプリ マニフェストの PressAndHoldStart 要素と PressAndHoldStop 要素で指定した値が含まれます。
// App.xaml.cs
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
var eventargs = AppInstance.GetCurrent().GetActivatedEventArgs();
string state = "";
if ((eventargs != null) && (eventargs.Kind == ExtendedActivationKind.Protocol))
{
var protocolArgs = (Windows.ApplicationModel.Activation.ProtocolActivatedEventArgs)eventargs.Data;
WwwFormUrlDecoder decoderEntries = new WwwFormUrlDecoder(protocolArgs.Uri.Query);
state = Uri.UnescapeDataString(decoderEntries.GetFirstValueByName("state"));
}
state = (state == "") ? "Launched" : state;
m_window = new MainWindow(state);
m_window.Activate();
}
重要
既定では、WinUI アプリは複数インスタンス化されています。つまり、Microsoft Copilotホット キーが押されたり離されたりするたびに、新しいインスタンスが起動されます。 これは多くのプロバイダーにとって望ましい動作かもしれませんが、必要に応じて、1 つのインスタンスを使用するようにアプリを更新できます。 詳細については、「 C# を使用して単一インスタンス WinUI アプリを作成する」を参照してください。
高速パス呼び出しを処理する
URI のアクティブ化に加えて、アプリは、実行中のアプリがウィンドウ メッセージを介して Copilot ハードウェア アプリに関するメッセージを受信する高速パス呼び出しをサポートするために登録できます。 現在実行中のアプリの場合、この呼び出しメソッドは URI のアクティブ化よりも高速であり、キーを押して保持した後にアプリで音声のリッスンを迅速に開始できるため、ユーザー エクスペリエンスが向上します。
高速パス呼び出しをサポートするようにアプリ マニフェスト ファイルを更新する
高速パス呼び出しのサポートを追加するには、"com.microsoft.windows.copilotkeyprovider" 拡張機能を更新して、SingleTap、PressAndHoldStart、および PressAndHoldStop 要素に MessageWParam 属性を追加します。 各 MessageWParam 値は一意の 32 ビット整数である必要がありますが、使用される値はアプリによって選択されます。 この例では、それぞれ 0、1、2 の値を使用します。 これらの値は、Windows メッセージの wParam パラメーターで渡され、Windows Copilot ハードウェア キーの現在の押された状態を判断するときに、この例の後半で使用されます。
<!-- Package.appxmanifest -->
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.copilotkeyprovider"
Id="MyAppId"
DisplayName="App display name"
Description="App description"
PublicFolder="Public">
<uap3:Properties>
<SingleTap MessageWParam="0">myapp-copilothotkey://?state=Tap</SingleTap>
<PressAndHoldStart MessageWParam="1">myapp-copilothotkey://?state=Down</PressAndHoldStart>
<PressAndHoldStop MessageWParam="2">myapp-copilothotkey://?state=Up</PressAndHoldStop>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
ウィンドウ登録用の win32 API をAccessする
高速パスのアクティブ化は、アプリのいずれかのウィンドウに関連付けられている IPropertyStore にプロパティを設定することで有効になります。 これを行うには、一部のネイティブ Win32 API へのアクセスが必要です。 このチュートリアルでは、C# バインドの生成を自動化し、NuGet パッケージとして使用できる CsWin32 ライブラリを使用します。
Visual Studioの Solution Explorer で、project ファイルを右クリックし、Manage NuGet パッケージを選択します。。NuGet package managerの Browse タブで、"cswin32" を検索し、"Microsoft.Windows.CsWin32" パッケージを選択し、*Install をクリックします。
パッケージがインストールされたら、project ディレクトリに新しいテキスト ファイルを追加し、"NativeMethods.txt" という名前を付けます。 CsWin32 ツールは、バインドを生成する Win32 API の一覧をこのファイルで検索します。 "NativeMethods.txt" に次の API 名を入力します。
SUBCLASSPROC
SHGetPropertyStoreForWindow
IPropertyStore
SetWindowSubclass
DefSubclassProc
Microsoft Copilot向けfastpath呼び出しのウィンドウを登録する
次に、 MainWindow クラスを更新して、Copilot ハードウェア キーから fastpath 呼び出しを受け取るウィンドウを登録します。
まず、GetWindowHandle を呼び出して、MainWindow への HWND ハンドルを取得します。 SHGetPropertyStoreForWindow を呼び出して、ウィンドウの IPropertyStore を取得します。 新しい PROPERTYKEY を 作成し、 fmtid メンバーを Windows Copilot fastpath アクティブ化の GUID に設定します。 プロパティの値をアプリ定義の値に設定します。この値は、ハードウェア キーの状態が変化したときにシステムからアプリに返されます。 アプリ定義の値は、WM_APP範囲内にある必要がある Windows メッセージ ID です。 詳細については、 WM_APPを参照してください。 SetValue を呼び出し、Commit を呼び出してプロパティ ストアに変更をコミットします。
最後に、ハードウェア キーの状態が変化したときに呼び出される サブクラスPROC コールバックを作成します。 WindowSubClass は、次の手順で示すコールバック実装です。 SetWindowSubclass を呼び出してコールバックを登録します。
private HWND hWndMain;
private Windows.Win32.UI.Shell.SUBCLASSPROC SubClassDelegate;
public const int WM_COPILOT = 0x8000 + 0x0001;
public MainWindow(string state)
{
this.InitializeComponent();
hWndMain = (HWND)WinRT.Interop.WindowNative.GetWindowHandle(this);
Microsoft.UI.Windowing.AppWindow appWindow = AppWindow;
var propertyStoreGUID = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
var hr = PInvoke.SHGetPropertyStoreForWindow((HWND)this.AppWindow.Id.Value, in propertyStoreGUID, out var propertyStore);
var key = new PROPERTYKEY();
var copilotFastpathGUID = new Guid("38652BCA-4329-4E74-86F9-39CF29345EEA");
key.fmtid = copilotFastpathGUID;
key.pid = 0x00000002;
var value = new PROPVARIANT();
value.Anonymous.Anonymous.vt = VARENUM.VT_UINT;
value.Anonymous.decVal = WM_COPILOT;
((IPropertyStore)propertyStore).SetValue(in key, in value);
((IPropertyStore)propertyStore).Commit();
SubClassDelegate = new Windows.Win32.UI.Shell.SUBCLASSPROC(WindowSubClass);
bool bRet = PInvoke.SetWindowSubclass((HWND)appWindow.Id.Value, SubClassDelegate, 0, 0);
_state = state;
}
ウィンドウ サブクラス コールバックを実装する
この例の最後の手順は、アプリが実行され、Windows Copilot ハードウェア キーの状態が変更されるたびに呼び出されるウィンドウ サブクラス コールバックを実装することです。 この例では、前の手順でプロパティ ストアの値を設定するときに指定した WM_COPILOT 値がウィンドウ メッセージであることを確認します。 次に、 wParam 引数の値を調べて、アプリ マニフェストで MessageWParam 属性で指定した値のうち、どの値が渡されたかを確認します。 現在の 状態で UI を更新するために SetState が呼び出されます。
private LRESULT WindowSubClass(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
{
switch (uMsg)
{
case WM_COPILOT:
{
switch (wParam.Value)
{
case 0:
SetState("SingleTap");
break;
case 1:
SetState("PressAndHold START");
break;
case 2:
SetState("PressAndHold END");
break;
}
}
break;
}
return PInvoke.DefSubclassProc((HWND)hWnd, uMsg, wParam, lParam);
}
Windows Copilot ハードウェア キー プロバイダーに署名する
Microsoft Copilot ハードウェア キーのターゲットとして有効にするには、プロバイダー アプリにサインインする必要があります。 アプリのパッケージ化と署名の詳細については、「 Visual Studio でデスクトップまたは UWP アプリをパッケージ化する」を参照してください。
Windows developer