Verarbeiten von Microsoft Copilot Hardware-Schlüsselstatusänderungen

In diesem Artikel wird beschrieben, wie Apps registriert werden können, um aktiviert zu werden und Benachrichtigungen zu erhalten, wenn die Microsoft Copilot Hardware-Taste oder die Windows-Taste + C gedrückt, gedrückt gehalten und losgelassen wird. Mit diesem Feature können Apps unterschiedliche Aktionen ausführen, je nachdem, welche Schlüsselstatusänderung erkannt wird. Eine App kann z. B. eine normale Aktivierung ausführen, wenn die Taste einfach gedrückt wird, aber einen Screenshot erstellen, wenn die Taste gedrückt und gehalten wird. Oder eine App kann mit der Aufzeichnung von Audio beginnen und einen Statusindikator anzeigen, dass Audio aufgezeichnet wird, wenn die Taste gedrückt und gehalten wird, und dann die Aufzeichnung von Audio beenden, wenn die Taste losgelassen wird. Die Taste muss gedrückt und für mindestens 300 ms gehalten werden, um in den gehaltenen Zustand zu gelangen.

Dieses Feature erweitert die Features eines grundlegenden Microsoft Copilot Hardwareschlüsselanbieters, der einfach registriert wird, um gestartet zu werden, wenn die Hardwaretaste gedrückt wird. Weitere Informationen finden Sie unter Microsoft Copilot Hardwareschlüsselanbieter.

Der Rest dieses Artikels führt Sie durch die Erstellung einer einfachen C#WinUI 3-App, die auf die Aktivierung reagiert, die von einem einzelnen Drücken oder einem Drücken und Halten und Freigeben der Schaltfläche Microsoft Copilot initiiert wird.

Neues Projekt erstellen

Erstellen Sie in Visual Studio ein neues Projekt. Legen Sie in diesem Beispiel im Dialogfeld " Neues Projekt erstellen " den Sprachfilter auf C# und den Projekttyp auf "WinUI" fest, und wählen Sie dann "WinUI Blank App (Paket)" aus.

Eine Eigenschaft hinzufügen, um den Zustand der gedrückten Microsoft Copilot-Taste zu verfolgen.

In diesem Beispiel erstellen wir eine Eigenschaft namens "Status ", die zum Anzeigen des aktuellen Aktivierungszustands in der Benutzeroberfläche verwendet wird. Fügen Sie in der Definition von MainWindow.xaml.cs den folgenden Code hinzu, um eine Zeichenfolgeneigenschaft zu erstellen, an die in unserer XAML-Datei gebunden werden kann.

// 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();
        }
    }
}

Fügen Sie der Benutzeroberfläche ein TextBox-Steuerelement hinzu, um den aktuellen Aktivierungsstatus der App anzuzeigen. Ersetzen Sie das standardmäßige StackPanel-Element in "MainPage.xaml" durch den folgenden Code.

<!-- MainWindow.xaml -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBlock Name="KeyStateText" Text="{x:Bind State, Mode=OneWay}" />
</StackPanel>

Aktualisieren Sie schließlich den MainWindow-Konstruktor , um ein Argument zu verwenden, das die Statuseigenschaft beim Erstellen des Fensters festgelegt.

// MainWindow.xaml.cs
public MainWindow(string state)
{
    this.InitializeComponent();

    _state = state;
}

Registrieren für die URI-Aktivierung

Das System startet Microsoft Copilot Hardware-Schlüsselanbieter mithilfe der URI-Aktivierung. Registrieren Sie ein Startprotokoll, indem Sie das uap:Protocol-Element zu Ihrem App-Manifest hinzufügen. Weitere Informationen zum Registrieren als Standardhandler für ein URI-Schema finden Sie unter Behandeln der URI-Aktivierung.

Das folgende Beispiel zeigt die Registrierung des URI-Schemas "myapp-copilothotkey" mit 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 Hardware-Schlüssel-App-Erweiterung

Eine App muss gepackt werden, um sich als Microsoft Copilot Hardwareschlüsselanbieter zu registrieren. Informationen zum Verpacken von Apps finden Sie unter An overview of Package Identity in Windows app. Microsoft Copilot Hardwareschlüsselanbieter deklarieren ihre Registrierungsinformationen im uap3:AppExtension. Das Name-Attribut der Erweiterung muss auf "com.microsoft.windows.copilotkeyprovider" festgelegt werden. Um die Schlüsselstatusänderungen zu unterstützen, müssen Apps einige zusätzliche Einträge für ihre uap3:AppExtension-Deklaration bereitstellen.

Fügen Sie innerhalb des uap3:AppExtension-Elements ein uap3:Properties-Element mit untergeordneten Elementen PressAndHoldStart und PressAndHoldStop hinzu. Der Inhalt dieser Elemente sollte der URI des im Manifest im vorherigen Schritt registrierten Protokollschemas sein. Die Abfragezeichenfolgenargumente geben an, ob der URI gestartet wird, weil der Benutzer die Hot-Taste gedrückt und gehalten hat oder weil der Benutzer die Hot-Taste losgelassen hat. Die App verwendet diese Abfragezeichenfolgenwerte während der App-Aktivierung, um die richtige Auszuführende Aktion zu bestimmen. Das Angeben des SingleTap-Elements ist optional, kann jedoch hilfreich sein, um festzustellen, ob die App über den Copilot-Hardwareschlüssel gestartet wurde.

<!-- 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> 
  ...

Behandeln der URI-Aktivierung

Um festzustellen, ob die App über die URI-Aktivierung aktiviert wurde, rufen Sie "AppInstance.GetActivatedEventArgs " auf, und überprüfen Sie, ob der Wert der AppActivationArguments.Kind-EigenschaftProtokoll ist. Wenn die App über die Protokollaktivierung gestartet wurde, überprüfen Sie, ob das URI-Schema mit dem Protokollnamen übereinstimmt, den Sie im App-Manifest angegeben haben. Wenn alle diese Tests bestehen, wissen Sie, dass Ihre App vom Benutzer aktiviert wurde, der die Copilot-Hardwaretaste drückt. An diesem Punkt können Sie die URI-Abfragezeichenfolge analysieren und den Zustandsparameter abrufen, der die Werte enthält, die Sie in den Elementen PressAndHoldStart und PressAndHoldStop im App-Manifest angegeben haben.

// 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();
}

Wichtig

Beachten Sie, dass WinUI-Apps standardmäßig mehrfach instanziiert sind. Das bedeutet, dass eine neue Instanz gestartet wird, wann immer die Schnelltaste von Microsoft Copilot gedrückt oder losgelassen wird. Dies kann das gewünschte Verhalten für viele Anbieter sein, aber wenn Sie es vorziehen, können Sie die App aktualisieren, um eine einzelne Instanz zu verwenden. Weitere Informationen finden Sie unter Erstellen einer Single-Instanced-WinUI-App mit C#.

Schnelle Pfadaufrufe behandeln

Zusätzlich zur URI-Aktivierung können Apps registriert werden, um den schnellen Pfadaufruf zu unterstützen, bei dem eine ausgeführte App Nachrichten über die Copilot-Hardware-App über Fenstermeldungen empfängt. Bei einer derzeit ausgeführten App ist diese Aufrufmethode schneller als die URI-Aktivierung und bietet eine bessere Benutzererfahrung, da die App schneller mit der Spracherkennung beginnen kann, nachdem die Taste gedrückt und gehalten wurde.

Aktualisieren der App-Manifestdatei zur Unterstützung des schnellen Pfadaufrufs

Um Unterstützung für schnelle Pfadaufrufe hinzuzufügen, aktualisieren Sie die Erweiterung "com.microsoft.windows.copilotkeyprovider", um das MessageWParam-Attribut zu den Elementen SingleTap, PressAndHoldStart und PressAndHoldStop hinzuzufügen. Jeder MessageWParam-Wert muss eine eindeutige 32-Bit-Ganzzahl sein, aber die verwendeten Werte werden von der App ausgewählt. In diesem Beispiel werden die Werte 0, 1 und 2 verwendet. Diese Werte werden später im Beispiel verwendet, wenn sie im wParam-Parameter einer Windows-Nachricht übergeben werden, um den aktuellen gedrückten Zustand des Windows Copilot-Hardwareschlüssels zu bestimmen.

<!-- 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>

Zugriff auf Win32-APIs für die Fenster-Registrierung

Die Aktivierung des schnellen Pfads wird aktiviert, indem eine Eigenschaft für den IPropertyStore festgelegt wird, der einem der Fenster der App zugeordnet ist. Um dies zu tun, erfordert es Zugriff auf einige native Win32-APIs. In dieser exemplarischen Vorgehensweise wird die CsWin32-Bibliothek verwendet, die die Generierung von C#-Bindungen automatisiert und als NuGet-Paket verfügbar ist.

Klicken Sie in Visual Studio in Solution Explorer mit der rechten Maustaste auf Ihre project Datei, und wählen Sie Manage NuGet-Pakete aus... . Suchen Sie auf der Registerkarte Browse der NuGet-package manager nach "cswin32", und wählen Sie das Paket "Microsoft.Windows.CsWin32" aus, und klicken Sie auf *Install.

Fügen Sie nach der Installation des Pakets eine neue Textdatei in Ihrem project Verzeichnis hinzu, und nennen Sie es "NativeMethods.txt". Das CsWin32-Tool sucht in dieser Datei nach einer Liste der Win32-APIs, für die Bindungen generiert werden. Fügen Sie die folgenden API-Namen in "NativeMethods.txt" ein.

SUBCLASSPROC

SHGetPropertyStoreForWindow

IPropertyStore

SetWindowSubclass

DefSubclassProc

Registrieren des Fensters für Microsoft Copilot fastpath-Aufruf

Als Nächstes aktualisieren wir die MainWindow-Klasse, um das Fenster zu registrieren und Fastpath-Aufrufe vom Copilot-Hardwareschlüssel zu empfangen.

Rufen Sie zunächst GetWindowHandle auf, um ein HWND-Handle für mainWindow abzurufen. Rufen Sie SHGetPropertyStoreForWindow auf, um den IPropertyStore für das Fenster abzurufen. Erstellen Sie einen neuen PROPERTYKEY, und legen Sie das fmtid-Element auf die GUID für die Windows Copilot-FastPath-Aktivierung fest. Legen Sie den Wert der Eigenschaft auf einen app-definierten Wert fest, der vom System zurück an die App übergeben wird, wenn sich der Zustand des Hardwareschlüssels ändert. Der von der App definierte Wert ist die Windows-Nachrichten-ID, die sich im WM_APP Bereich befinden muss. Weitere Informationen finden Sie unter WM_APP. Rufen Sie SetValue auf, und rufen Sie dann Commit auf, um die Änderung an den Eigenschaftenspeicher zu übernehmen.

Erstellen Sie schließlich einen SUBCLASSPROC-Rückruf , der aufgerufen wird, wenn sich der Zustand des Hardwareschlüssels ändert. WindowSubClass ist die Rückrufimplementierung, die im nächsten Schritt angezeigt wird. Rufen Sie SetWindowSubclass auf, um den Rückruf zu registrieren.

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;
}

Implementieren Sie den Rückruf der Fenster-Unterklasse

Der letzte Schritt in diesem Beispiel ist die Implementierung des Rückrufs der Fenster-Unterklasse, der immer dann aufgerufen wird, wenn die App läuft und sich der Status der Windows Copilot-Hardware-Taste ändert. In diesem Beispiel wird überprüft, ob die Fenstermeldung der WM_COPILOT Wert ist, den wir beim Festlegen des Eigenschaftsspeicherwerts im vorherigen Schritt angegeben haben. Anschließend überprüfen wir den Wert des wParam-Arguments , um zu sehen, welche werte wir mit den MessageWParam-Attributen im App-Manifest angegeben haben. SetState wird aufgerufen, um die Benutzeroberfläche mit dem aktuellen Zustand zu aktualisieren.

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);

}

Signieren des Windows Copilot-Hardwareschlüsselanbieters

Anbieter-Apps müssen angemeldet sein, um als Ziel des Microsoft Copilot Hardwareschlüssels aktiviert zu werden. Informationen zum Verpacken und Signieren Ihrer App finden Sie unter Package einer Desktop- oder UWP-App in Visual Studio.