Gestire le modifiche dello stato della chiave hardware Microsoft Copilot

Questo articolo descrive come le app possono registrarsi per essere attivate e ricevere notifiche quando viene premuto, tenuto premuto e rilasciato il tasto hardware Microsoft Copilot o il tasto Windows + C. Questa funzione consente alle app di eseguire diverse azioni a seconda di quale cambiamento di stato dei tasti viene rilevato. Ad esempio, un'app può eseguire l'attivazione normale quando il tasto viene premuto una volta, ma catturare uno screenshot quando il tasto viene premuto e tenuto premuto. Oppure, un'app può iniziare a registrare audio e mostrare un indicatore di stato che segnala che l'audio è in registrazione quando il tasto viene premuto e tenuto premuto, e poi interrompere la registrazione dell'audio quando il tasto viene rilasciato. Per passare allo stato tenuto, il tasto deve essere premuto e mantenuto per almeno 300 ms.

Questa funzionalità amplia le capacità di un fornitore di chiave hardware di base Microsoft Copilot, che viene semplicemente registrato per essere avviato quando si preme il tasto hardware. Per altre informazioni, vedere Microsoft Copilot provider di chiavi hardware.

Il resto di questo articolo illustra la creazione di una semplice app WinUI 3 C# che risponde all'attivazione avviata da una singola pressione o da una pressione e un rilascio del pulsante Microsoft Copilot.

Creare un nuovo project

In Visual Studio creare un nuovo project. Per questo esempio, nella finestra di dialogo Crea un nuovo progetto impostare il filtro del linguaggio su C# e il tipo di progetto su WinUI e quindi selezionare "App vuota WinUI (in pacchetto)".

Aggiungere una proprietà per tenere traccia dello stato del tasto premuto di Microsoft Copilot.

In questo esempio verrà creata una proprietà denominata State che verrà usata per visualizzare lo stato di attivazione corrente nell'interfaccia utente. In MainWindow.xaml.cs, all'interno della definizione di MainWindow aggiungere il codice seguente per creare una proprietà stringa a cui è possibile eseguire il binding nel file 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();
        }
    }
}

Aggiungere un controllo TextBlock all'interfaccia utente per visualizzare lo stato di attivazione corrente dell'app. Sostituire l'elemento StackPanel predefinito in MainWindow.xaml con il codice seguente.

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

Aggiornare infine il costruttore MainWindow per accettare un argomento che imposta la proprietà State al momento della creazione della finestra.

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

    SetState(state);
}

Registrarsi per l'attivazione dell'URI

Il sistema avvia i provider di chiavi hardware di Microsoft Copilot usando l'attivazione URI. Registrare un protocollo di avvio aggiungendo l'elemento uap:Protocol al manifesto dell'app. Per altre informazioni su come eseguire la registrazione come gestore predefinito per uno schema URI, vedere Gestire l'attivazione URI.

L'esempio seguente illustra uap:Extension che registra lo schema URI "myapp-copilothotkey".

<!-- 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 estensione dell'applicazione per chiavi hardware

Un'app deve essere inserita in un pacchetto per eseguire la registrazione come provider di chiavi hardware Microsoft Copilot. Per informazioni sulla creazione di pacchetti di app, vedere Panoramica dell'identità del pacchetto in Windows app. I provider di chiavi hardware di Microsoft Copilot dichiarano le informazioni di registrazione all'interno del uap3:AppExtension. L'attributo Name dell'estensione deve essere impostato su "com.microsoft.windows.copilotkeyprovider". Per supportare le modifiche dello stato della chiave, le app devono fornire alcune voci aggiuntive alla dichiarazione uap3:AppExtension .

All'interno dell'elemento uap3:AppExtension aggiungere un elemento uap3:Properties con elementi figlio PressAndHoldStart e PressAndHoldStop. Il contenuto di questi elementi dovrebbe essere l'URI dello schema del protocollo registrato nel manifesto nel passaggio precedente. Gli argomenti della stringa di query specificano se l'URI viene avviato perché l'utente ha premuto e mantenuto il tasto di scelta rapida o perché l'utente ha rilasciato il tasto di scelta rapida. L'app utilizza questi valori della stringa di query durante l'attivazione dell'app per determinare l'azione corretta da intraprendere. Specificare l'elemento SingleTap è facoltativo, ma può essere utile per determinare se l'app è stata avviata dalla chiave hardware di 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> 
  ...

Gestire l'attivazione dell'URI

Per rilevare se l'app è stata attivata tramite l'attivazione URI, chiamare AppInstance.GetActivatedEventArgs e verificare se il valore della proprietà AppActivationArguments.Kind è Protocol. Se l'app è stata avviata tramite attivazione del protocollo, verifica se lo schema URI è lo stesso del nome del protocollo che hai specificato nel manifesto dell'app. Se tutti questi test vengono superati, saprai che la tua app è stata attivata dall'utente premendo il tasto hardware Copilot. A questo punto è possibile analizzare la stringa di query URI e ottenere il parametro state , che avrà i valori specificati negli elementi PressAndHoldStart e PressAndHoldStop nel manifesto dell'app.

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

Importante

Si noti che, per impostazione predefinita, le app WinUI sono multiistanza, il che significa che verrà avviata una nuova istanza ogni volta che viene premuto o rilasciato il tasto di scelta rapida Microsoft Copilot. Potrebbe essere il comportamento desiderato per molti provider, ma se preferisci, puoi aggiornare la tua applicazione per utilizzare una singola istanza. Per altre informazioni, vedere Creare un'app WinUI a istanza singola con C#.

Gestire l'invocazione del percorso rapido

Oltre all'attivazione tramite URI, le app possono registrarsi per supportare l'invocazione rapida, in cui un'app in esecuzione riceve messaggi sull'app hardware Copilot tramite messaggi di finestra. Per un'app attualmente in esecuzione, questo metodo di chiamata è più veloce rispetto all'attivazione dell'URI e offre un'esperienza utente migliore, poiché l'app può iniziare ad ascoltare il riconoscimento vocale più rapidamente dopo che il tasto viene premuto e mantenuto.

Aggiorna il file manifest dell'app per supportare l'invocazione rapida del percorso

Per aggiungere il supporto per la chiamata al percorso rapido, aggiornare l'estensione "com.microsoft.windows.copilotkeyprovider" per aggiungere l'attributo MessageWParam agli elementi SingleTap, PressAndHoldStart e PressAndHoldStop . Ogni valore MessageWParam deve essere un intero univoco a 32 bit, ma i valori usati vengono scelti dall'app. Questo esempio utilizza i valori di 0, 1 e 2, rispettivamente. Questi valori verranno usati più avanti nell'esempio quando vengono passati nel parametro wParam di un messaggio di Windows per determinare lo stato corrente premuto del tasto hardware di 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>

Access API win32 per la registrazione delle finestre

L'attivazione rapida del percorso è abilitata impostando una proprietà in IPropertyStore associata a una delle finestre dell'app. Per fare ciò è necessario avere accesso ad alcune API Win32 native. Questo tutorial utilizzerà la libreria CsWin32, che automatizza la generazione di binding C# ed è disponibile come pacchetto NuGet.

In Visual Studio, in Esplora soluzioni fare clic con il pulsante destro del mouse sul file project e selezionare Gestisci pacchetti NuGet... . Nella scheda Browse della package manager NuGet cercare "cswin32" e selezionare il pacchetto "Microsoft.Windows.CsWin32" e fare clic su *Install.

Dopo aver installato il pacchetto, aggiungere un nuovo file di testo nella directory project e denominarlo "NativeMethods.txt". Lo strumento CsWin32 cercherà in questo file un elenco delle API Win32 per cui genererà associazioni. Inserire i seguenti nomi API in "NativeMethods.txt".

SUBCLASSPROC

SHGetPropertyStoreForWindow

IPropertyStore

SetWindowSubclass

DefSubclassProc

Registrare la finestra per l'invocazione fastpath di Microsoft Copilot

Successivamente aggiorneremo la classe MainWindow per registrare la finestra per ricevere chiamate fastpath dalla chiave hardware di Copilot.

Prima di tutto, chiama GetWindowHandle per ottenere un handle HWND a MainWindow. Chiama SHGetPropertyStoreForWindow per ottenere IPropertyStore per la finestra. Creare un nuovo PROPERTYKEY e impostare il membro fmtid sul GUID per l'attivazione fastpath di Windows Copilot. Imposta il valore della proprietà su un valore definito dall'app, che sarà restituito all'app dal sistema quando lo stato del tasto hardware cambia. Il valore definito dall'app è l'ID del messaggio di Windows, che deve rientrare nell'intervallo WM_APP. Per altre informazioni, vedere WM_APP. Chiamare SetValue e quindi chiamare Commit per applicare la modifica nel repository delle proprietà.

Creare infine un callback SUBCLASSPROC che verrà chiamato quando cambia lo stato della chiave hardware. WindowSubClass è l'implementazione del callback che verrà visualizzata nel passaggio successivo. Chiama SetWindowSubclass per registrare il callback.

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

    var propertyStoreGUID = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
    var hr = PInvoke.SHGetPropertyStoreForWindow(hWndMain, 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(hWndMain, SubClassDelegate, 0, 0);

    SetState(state);
}

Implementa il callback della sottoclasse finestra

L'ultimo passo in questo esempio è implementare il callback della sottoclasse della finestra che verrà chiamato ogni volta che l'app è in esecuzione e lo stato del tasto hardware di Windows Copilot cambia. In questo esempio, verifichiamo che il messaggio della finestra sia il valore WM_COPILOT che abbiamo specificato quando si imposta il valore dell'archivio delle proprietà nel passaggio precedente. Poi controlliamo il valore dell'argomento wParam per vedere quale dei valori che abbiamo specificato con gli attributi MessageWParam nel manifesto dell'app è stato passato. SetState viene chiamato per aggiornare l'interfaccia utente con lo stato corrente.

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

}

Firma il fornitore di chiavi hardware per Windows Copilot

Le app del provider devono essere firmate per poter essere abilitate come destinazione della chiave hardware Microsoft Copilot. Per informazioni sulla creazione di pacchetti e la firma dell'app, vedi Pacchetto di un'app desktop o UWP in Visual Studio.