Menangani perubahan status kunci perangkat keras Microsoft Copilot

Artikel ini menjelaskan bagaimana aplikasi dapat mendaftar untuk diaktifkan dan menerima pemberitahuan saat kunci perangkat keras Microsoft Copilot atau tombol Windows + C ditekan, ditekan dan ditahan, dan dirilis. Fitur ini memungkinkan aplikasi untuk melakukan tindakan yang berbeda tergantung pada perubahan status kunci mana yang terdeteksi. Misalnya, aplikasi dapat melakukan aktivasi normal saat tombol ditekan tunggal, tetapi mengambil cuplikan layar saat tombol ditekan dan ditahan. Atau, aplikasi dapat mulai merekam audio dan menampilkan indikator status bahwa audio sedang direkam saat tombol ditekan dan ditahan, lalu berhenti merekam audio saat tombol dirilis. Tombol harus ditekan dan ditahan setidaknya selama 300 ms untuk pindah ke keadaan tertahan.

Fitur ini memperluas fitur penyedia kunci perangkat keras dasar Microsoft Copilot, yang hanya mendaftar untuk diluncurkan saat kunci perangkat keras ditekan. Untuk informasi selengkapnya, lihat penyedia kunci perangkat keras Microsoft Copilot.

Sisa artikel ini akan membahas pembuatan aplikasi C# WinUI 3 sederhana yang merespons aktivasi yang dimulai oleh satu tekan atau tekan dan tahan dan lepaskan tombol Microsoft Copilot.

Membuat project baru

Di Visual Studio, buat project baru. Untuk contoh ini, dalam dialog Buat proyek baru , atur filter bahasa ke C# dan jenis proyek ke WinUI lalu pilih "WinUI Blank App (Packaged)".

Menambahkan properti untuk melacak status tombol Microsoft Copilot yang ditekan

Dalam contoh ini, kita akan membuat properti bernama State yang akan kita gunakan untuk menampilkan status aktivasi saat ini di UI. Dalam MainWindow.xaml.cs, di dalam definisi MainWindow tambahkan kode berikut untuk membuat properti string yang dapat kita ikat dalam file XAML kita.

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

Tambahkan kontrol TextBox ke UI untuk menampilkan status aktivasi aplikasi saat ini. Ganti elemen StackPanel default di MainPage.xaml dengan kode berikut.

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

Terakhir, perbarui konstruktor MainWindow untuk mengambil argumen yang akan mengatur properti Status saat jendela dibuat.

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

    _state = state;
}

Daftar untuk aktivasi URI

Sistem meluncurkan penyedia kunci perangkat keras Microsoft Copilot menggunakan aktivasi URI. Daftarkan protokol peluncuran dengan menambahkan elemen uap:Protocol ke manifes aplikasi Anda. Untuk informasi selengkapnya tentang cara mendaftar sebagai handler default untuk skema URI, lihat Menangani aktivasi URI.

Contoh berikut menunjukkan uap:Extension yang mendaftarkan skema 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 ekstensi aplikasi kunci perangkat keras

Aplikasi harus dipaketkan untuk mendaftar sebagai penyedia kunci perangkat keras Microsoft Copilot. Untuk informasi tentang kemasan aplikasi, lihat Gambaran umum Identitas Paket di Windows app. Microsoft Copilot penyedia kunci perangkat keras mendeklarasikan informasi pendaftaran mereka dalam uap3:AppExtension. Atribut Nama dari ekstensi harus disetel ke "com.microsoft.windows.copilotkeyprovider". Untuk mendukung perubahan status kunci, aplikasi harus menyediakan beberapa entri tambahan ke deklarasi uap3:AppExtension mereka.

Di dalam elemen uap3:AppExtension, tambahkan elemen uap3:Properties dengan sub-elemen PressAndHoldStart dan PressAndHoldStop. Konten elemen-elemen ini harus menjadi URI dari skema protokol yang terdaftar dalam manifes pada langkah sebelumnya. Argumen kueri string menunjukkan apakah URI diluncurkan karena pengguna menekan dan menahan tombol pintas atau karena pengguna melepas tombol pintas. Aplikasi ini menggunakan nilai string kueri ini selama aktivasi aplikasi untuk menentukan tindakan yang benar untuk diambil. Menentukan elemen SingleTap bersifat opsional tetapi dapat berguna untuk menentukan apakah aplikasi diluncurkan dari kunci perangkat keras 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> 
  ...

Pengelolaan aktivasi URI

Untuk mendeteksi apakah aplikasi diaktifkan melalui aktivasi URI, panggil AppInstance.GetActivatedEventArgs dan periksa untuk melihat apakah nilai properti AppActivationArguments.Kind adalah Protokol. Jika aplikasi diluncurkan melalui aktivasi protokol, periksa untuk melihat apakah skema URI sama dengan nama protokol yang Anda tentukan dalam manifes aplikasi Anda. Jika semua pengujian ini lulus, maka Anda tahu bahwa aplikasi Anda diaktifkan oleh pengguna yang menekan kunci perangkat keras Copilot. Pada titik ini Anda dapat mengurai string kueri URI dan mendapatkan parameter status , yang akan memiliki nilai yang Anda tentukan dalam elemen PressAndHoldStart dan PressAndHoldStop dalam manifes aplikasi.

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

Penting

Perhatikan bahwa, secara bawaan, aplikasi WinUI bersifat multi-instans, yang berarti bahwa instans baru akan diluncurkan setiap kali tombol pintas Microsoft Copilot ditekan. Ini mungkin perilaku yang diinginkan untuk banyak penyedia, tetapi jika Anda mau, Anda dapat memperbarui aplikasi Anda untuk menggunakan satu instans. Untuk informasi selengkapnya, lihat Membuat aplikasi WinUI instans tunggal dengan C#.

Mengelola pemanggilan jalur cepat

Selain aktivasi URI, aplikasi dapat mendaftar untuk mendukung pemanggilan jalur cepat di mana aplikasi yang sedang berjalan menerima pesan tentang aplikasi perangkat keras Copilot melalui pesan jendela. Untuk aplikasi yang sedang berjalan, metode pemanggilan ini lebih cepat daripada aktivasi URI dan akan memberikan pengalaman pengguna yang lebih baik, karena aplikasi dapat mulai mendengarkan ucapan dengan lebih cepat setelah tombol ditekan dan ditahan.

Memperbarui file manifes aplikasi untuk mendukung pemanggilan jalur cepat

Untuk menambahkan dukungan untuk pemanggilan jalur cepat, perbarui ekstensi "com.microsoft.windows.copilotkeyprovider" untuk menambahkan atribut MessageWParam ke elemen SingleTap, PressAndHoldStart, dan PressAndHoldStop . Setiap nilai MessageWParam harus berupa bilangan bulat 32-bit yang unik, tetapi nilai yang digunakan dipilih oleh aplikasi. Contoh ini menggunakan nilai masing-masing 0, 1, dan 2. Nilai-nilai ini akan digunakan nanti dalam contoh ketika diteruskan dalam parameter wParam pesan Windows untuk menentukan status kunci perangkat keras Windows Copilot yang ditekan saat ini.

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

Akses API Win32 untuk pendaftaran jendela

Aktivasi jalur cepat diaktifkan dengan mengatur properti di IPropertyStore yang terkait dengan salah satu jendela aplikasi. Untuk melakukan ini memerlukan akses ke beberapa API Win32 bawaan. Panduan ini akan menggunakan pustaka CsWin32, yang mengotomatiskan pembuatan pengikatan C# dan tersedia sebagai paket NuGet.

Di Visual Studio, di Solution Explorer, klik kanan pada file project Anda dan pilih Kelola paket NuGet... . Pada tab Browse dari package manager NuGet, cari "cswin32" dan pilih paket "Microsoft.Windows.CsWin32" dan klik *Install.

Setelah paket diinstal, tambahkan file teks baru di direktori project Anda dan beri nama "NativeMethods.txt". Alat CsWin32 akan mencari daftar API Win32 dalam file ini untuk menghasilkan pengikatan. Masukkan nama API berikut di "NativeMethods.txt".

SUBCLASSPROC

SHGetPropertyStoreForWindow

IPropertyStore

SetWindowSubclass

DefSubclassProc

Daftarkan jendela untuk pemanggilan fastpath Microsoft Copilot

Selanjutnya kita akan memperbarui kelas MainWindow untuk mendaftarkan jendela untuk menerima pemanggilan fastpath dari kunci perangkat keras Copilot.

Pertama, panggil GetWindowHandle untuk mendapatkan handle HWND ke MainWindow. Panggil SHGetPropertyStoreForWindow untuk mendapatkan IPropertyStore untuk jendela. Buat PROPERTYKEY baru dan atur anggota fmtid ke GUID untuk aktivasi fastpath Windows Copilot. Atur nilai properti ke nilai yang ditentukan aplikasi, yang akan diteruskan kembali ke aplikasi dari sistem saat status kunci perangkat keras berubah. Nilai yang ditentukan aplikasi adalah ID pesan windows yang harus berada dalam rentang WM_APP. Untuk informasi selengkapnya, lihat WM_APP. Panggil SetValue lalu panggil Commit untuk mengkomit perubahan ke penyimpanan properti.

Terakhir, buat panggilan balik SUBCLASSPROC yang akan dipanggil saat status kunci perangkat keras berubah. WindowSubClass adalah implementasi panggilan balik yang akan ditampilkan pada langkah berikutnya. Hubungi SetWindowSubclass untuk mendaftarkan panggilan balik.

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

Mengimplementasikan callback subkelas jendela

Langkah terakhir dalam contoh ini adalah menerapkan panggilan balik subkelas jendela yang akan dipanggil setiap kali aplikasi berjalan dan status kunci perangkat keras Windows Copilot berubah. Dalam contoh ini, kami memeriksa bahwa pesan jendela adalah nilai WM_COPILOT yang kami tentukan saat mengatur nilai penyimpanan properti di langkah sebelumnya. Kemudian kita memeriksa nilai argumen wParam untuk melihat nilai mana yang kita tentukan dengan atribut MessageWParam dalam manifes aplikasi telah diteruskan. SetState dipanggil untuk memperbarui UI dengan status saat ini.

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

}

Menandatangani penyedia kunci perangkat keras Windows Copilot Anda

Aplikasi penyedia harus ditandatangani agar dapat diaktifkan sebagai target kunci perangkat keras Microsoft Copilot. Untuk informasi tentang pengemasan dan penandatanganan aplikasi Anda, lihat Paket desktop atau aplikasi UWP di Visual Studio.