Aksesibilitas papan ketik

Aksesibilitas keyboard harus diperlakukan sebagai model interaksi utama, bukan fallback sekunder. Pengalaman keyboard yang kuat mendukung pengguna yang memiliki berbagai disabilitas dan batasan (termasuk visi, pembelajaran, ketangkasan/mobilitas, dan disabilitas bahasa/komunikasi). Ini juga meningkatkan produktivitas bagi pengguna yang lebih suka berinteraksi dengan keyboard terlebih dahulu demi kecepatan dan presisi.

Jika akses keyboard tidak lengkap atau tidak konsisten, pengguna dapat kehilangan akses ke fungsionalitas aplikasi inti bahkan ketika interaksi pointer muncul sepenuhnya diimplementasikan.

Navigasi keyboard di antara elemen UI

Untuk berinteraksi dengan kontrol menggunakan keyboard, kontrol harus bisa difokuskan dan dapat dijangkau melalui perpindahan fokus. Untuk menerima fokus (tanpa menggunakan penunjuk), kontrol harus dapat diakses melalui navigasi tab. Secara default, urutan tab kontrol sama dengan urutan penambahannya ke surface desain, dideklarasikan dalam XAML, atau ditambahkan secara terprogram ke kontainer.

Di banyak UI, perilaku default ini dapat diterima dan selaras dengan alur baca. Namun, urutan visual dan urutan keyboard dapat berbeda tergantung pada tata letak kontainer dan posisi anak. Divergensi ini harus disengaja dan diuji.

Validasi perilaku tab secara eksplisit. Kisi, tabel, dan tata letak serupa adalah sumber umum ketidakcocokan antara urutan baca yang dirasakan dan urutan fokus. Uji jalur interaksi keyboard saja dan sentuh untuk memastikan traversal tetap efisien dan dapat diprediksi.

Untuk menyelaraskan traversal dengan aliran visual, Anda dapat merestrukturisasi XAML atau secara eksplisit menetapkan TabIndex. Contoh berikut menggunakan Kisi dengan pengurutan tab yang dimulai dari kolom terlebih dahulu.

<Grid>
  <Grid.RowDefinitions>...</Grid.RowDefinitions>
  <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>

  <TextBlock Grid.Column="1" HorizontalAlignment="Center">Groom</TextBlock>
  <TextBlock Grid.Column="2" HorizontalAlignment="Center">Bride</TextBlock>

  <TextBlock Grid.Row="1">First name</TextBlock>
  <TextBox x:Name="GroomFirstName" Grid.Row="1" Grid.Column="1" TabIndex="1"/>
  <TextBox x:Name="BrideFirstName" Grid.Row="1" Grid.Column="2" TabIndex="3"/>

  <TextBlock Grid.Row="2">Last name</TextBlock>
  <TextBox x:Name="GroomLastName" Grid.Row="2" Grid.Column="1" TabIndex="2"/>
  <TextBox x:Name="BrideLastName" Grid.Row="2" Grid.Column="2" TabIndex="4"/>
</Grid>

Dalam beberapa skenario, elemen harus dikecualikan dari tab traversal. Pendekatan standar adalah mengatur IsEnabled ke false, yang juga menonaktifkan interaksi. Kontrol yang dinonaktifkan secara otomatis dihapus dari urutan tab.

Jika elemen tetap interaktif melalui mekanisme lain tetapi tidak boleh dicapai dengan Tab, atur IsTabStop ke false.

Sebagian besar kontrol berkemampuan fokus disertakan dalam urutan tab secara default. Pengecualian umum adalah kontrol tampilan teks seperti RichTextBlock, yang dapat mendukung fokus untuk pemilihan teks dan operasi clipboard tetapi biasanya bukan perhentian tab karena bukan kontrol yang dapat dipanggil perintah. Kontrol ini masih dapat ditemukan oleh teknologi bantuan melalui semantik otomatisasi seperti pola kontrol Teks.

Baik Anda menggunakan tabIndex traversal default atau eksplisit, aturan berikut berlaku:

  • Jika TabIndex tidak diatur pada elemen, nilai defaultnya adalah Int32.MaxValue, dan urutan didasarkan pada urutan deklarasi/penyisipan.
  • Jika TabIndex diatur pada elemen:
    • Elemen dengan TabIndex sama dengan 0 ditambahkan berdasarkan urutan deklarasi/penyisipan.
    • Elemen dengan TabIndex yang lebih besar dari 0 ditambahkan dalam urutan TabIndex naik.
    • Elemen dengan TabIndex kurang dari 0 ditambahkan sebelum elemen dengan nilai nol.

Cuplikan berikut menunjukkan pengaturan TabIndex campuran (B menggunakan Int32.MaxValue, atau 2.147.483.647).

<StackPanel Background="#333">
  <StackPanel Background="#FF33FF">
    <Button>A</Button>
    <Button TabIndex="2147483647">B</Button>
    <Button>C</Button>
  </StackPanel>
  <StackPanel Background="#33FFFF">
    <Button TabIndex="1">D</Button>
    <Button TabIndex="1">E</Button>
    <Button TabIndex="0">F</Button>
  </StackPanel>
</StackPanel>

Ini menghasilkan urutan tab berikut:

  1. F
  2. D
  3. E
  4. A
  5. B
  6. C

Navigasi keyboard antar panel aplikasi dengan F6

Panel aplikasi adalah wilayah tugas yang menonjol di dalam jendela. Di Microsoft Edge, misalnya, panel menyertakan bilah alamat, bilah marka buku, strip tab, dan area konten. F6 umumnya digunakan untuk memindahkan fokus di antara panel-panel ini, di mana elemen-elemennya yang berada di dalamnya dapat diakses menggunakan navigasi keyboard standar.

Meskipun model navigasi keyboard yang sesuai adalah garis besar, model navigasi keyboard yang dapat digunakan juga biasanya mencakup:

  • Mendengarkan F6 untuk berpindah di antara area UI utama.
  • Menyediakan pintasan keyboard untuk perintah frekuensi tinggi.
  • Menyediakan kunci akses untuk kontrol penting.

Lihat Pintasan keyboard dan Tombol akses untuk panduan implementasi.

Optimalkan untuk F6

F6 secara signifikan mengurangi biaya traversal dengan memungkinkan pengguna melompat antar wilayah utama daripada menelusuri satu per satu kontrol anak.

Misalnya, dalam Microsoft Edge, F6 beralih antara bilah alamat, bilah favorit, strip tab, dan konten. Karena halaman dapat berisi banyak perhentian tab, ini membuat tugas navigasi umum jauh lebih efisien.

Urutan F6 dapat selaras dengan landmark atau judul, tetapi tidak perlu sama persis. Gunakan F6 untuk pergerakan tingkat wilayah yang luas dan landmark/judul untuk struktur semantik di dalam dan di seluruh wilayah.

Penting

Anda harus menerapkan navigasi F6 secara eksplisit di aplikasi Anda; tidak disediakan secara otomatis.

Jika memungkinkan, setiap wilayah target F6 harus memiliki nama yang dapat diakses dengan jelas, baik dari semantik landmark atau dengan mengatur AutomationProperties.Name pada akar wilayah.

Shift+F6 harus melintasi siklus yang sama dalam urutan terbalik.

Navigasi keyboard dalam elemen antarmuka pengguna

Kontrol gabungan harus menyediakan navigasi dalam yang dapat diprediksi antar elemen-elemen anak. Pola umumnya adalah menjaga akar komposit dalam urutan tab dan mengelola turunan aktif secara internal, daripada mengekspos setiap anak sebagai perhentian tab terpisah.

Banyak kontrol bawaan yang sudah menerapkan perilaku ini. Misalnya, traversal tombol panah tersedia secara default untuk ListView, GridView, ListBox, dan FlipView.

Alternatif papan ketik untuk tindakan dan kejadian penunjuk pada elemen kontrol yang spesifik

UI apa pun yang dapat diaktifkan oleh pointer juga harus dapat dipanggil oleh keyboard. Aktivasi mengharuskan elemen memiliki fokus (hanya kelas yang berasal dari Kontrol yang mendukung fokus dan navigasi tab).

Untuk kontrol yang dapat dipanggil, terapkan penanganan aktivitas keyboard untuk tombol Spacebar dan Enter. Ini menyediakan paritas keyboard dasar dengan interaksi pointer.

Jika elemen tidak mampu fokus secara default, gunakan jenis kontrol yang dapat difokuskan atau terapkan kontrol kustom dengan perilaku fokus eksplisit. Dalam hal ini, atur IsTabStop ke true dan berikan indikator fokus yang terlihat.

Dalam banyak kasus, komposisi lebih sederhana dan lebih tangguh dibandingkan dengan perilaku yang hanya menggunakan pointer. Misalnya, alih-alih menangani input pointer langsung pada Gambar, letakkan di dalam Tombol untuk mewarisi aktivasi keyboard, penanganan fokus, dan perilaku otomatisasi.

<!--Don't do this.-->
<Image Source="sample.jpg" PointerPressed="Image_PointerPressed"/>

<!--Do this instead.-->
<Button Click="Button_Click"
        AutomationProperties.Name="Open profile photo">
  <Image Source="Assets/profile-photo.png"/>
</Button>

Pintasan papan ketik

Selain navigasi dan aktivasi, terapkan pintasan (kombinasi kunci yang menyediakan akses efisien ke fungsionalitas aplikasi) untuk perintah penting atau sering digunakan dengan akselerator keyboard dan tombol akses.

Dua jenis pintasan umum adalah:

  • Akselerator: memanggil perintah secara langsung, dengan atau tanpa kontrol yang terlihat terkait.
  • Kunci akses: pindahkan fokus ke kontrol tertentu di UI Anda.

Selalu buat pintasan mudah ditemukan untuk pengguna teknologi bantuan. Komunikasikan melalui petunjuk alat, metadata otomatisasi, elemen UI yang terlihat, dan dokumentasi bantuan.

Untuk mengekspos metadata pintasan ke teknologi bantuan, gunakan AutomationProperties.AccessKey untuk pintasan mnemonic dan AutomationProperties.AcceleratorKey untuk pintasan perintah. Karena pembaca layar mungkin menyajikan ini dengan cara yang mirip, dokumentasikan pintasan-pintasan tersebut melalui beberapa saluran komunikasi.

Contoh berikut menunjukkan cara mendokumen kunci pintasan untuk tombol putar media, jeda, dan hentikan.

<Grid>

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <MediaPlayerElement x:Name="DemoPlayer"
    Width="500" Height="300" Margin="20"
    HorizontalAlignment="Center"
    AutoPlay="False"
    AreTransportControlsEnabled="True" />

  <StackPanel Grid.Row="1" Margin="10"
    Orientation="Horizontal" HorizontalAlignment="Center">

    <Button x:Name="PlayButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+P"
      AutomationProperties.AcceleratorKey="Ctrl+P"
      AutomationProperties.AccessKey="Alt+P">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="P"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Play</TextBlock>
    </Button>

    <Button x:Name="PauseButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+A"
      AutomationProperties.AcceleratorKey="Ctrl+A"
      AutomationProperties.AccessKey="Alt+A">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="A"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Pause</TextBlock>
    </Button>

    <Button x:Name="StopButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+S"
      AutomationProperties.AcceleratorKey="Ctrl+S"
      AutomationProperties.AccessKey="Alt+S">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="S"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Stop</TextBlock>
    </Button>
  </StackPanel>
</Grid>

Penting

Mengatur AutomationProperties.AcceleratorKey atau AutomationProperties.AccessKey tidak menerapkan perilaku keyboard. Properti ini mengekspos metadata ke Automasi UI sehingga teknologi bantuan dapat mengumumkan pintasan yang diharapkan.

Perilaku keyboard masih harus diimplementasikan dalam kode. Gunakan definisi KeyboardAccelerator deklaratif jika memungkinkan, dan gunakan pengendali KeyDown atau KeyUp ketika Anda membutuhkan logika perutean kustom. Perhatikan juga bahwa gaya garis bawah kunci akses tidak otomatis. Jika Anda ingin garis bawah mnemonik yang terlihat, render secara eksplisit (misalnya, dengan Garis Bawah).

Untuk kejelasan, sampel ini menghilangkan sumber string seperti "Ctrl+A". Dalam produksi, lokalkan teks pintasan dan validasi pilihan mnemonic per lokal, karena pemilihan kunci sering tergantung pada label yang diterjemahkan.

Untuk panduan tambahan, lihat Kunci pintasan di Panduan Interaksi Pengalaman Pengguna Windows.

Menerapkan penanganan kejadian kunci

Input utama menggunakan peristiwa yang dirutekan. Peristiwa yang dirutekan dapat menggelegak dari anak-anak ke kontainer induk, yang memungkinkan induk memproses pintasan untuk beberapa elemen turunan. Model kejadian ini nyaman untuk menentukan tindakan kunci pintasan untuk kontrol yang berisi beberapa elemen anak, yang tidak satu pun dapat memiliki fokus atau menjadi bagian dari urutan tab.

Untuk contoh kode yang menyertakan pemeriksaan tombol pengubah (misalnya, Ctrl), lihat Interaksi keyboard.

Navigasi keyboard untuk kontrol kustom

Untuk kontrol yang disesuaikan, gunakan tombol panah ketika sub-elemen terhubung secara spasial. Dalam skenario pohon di mana fungsi perluas/ciutkan dan aktivasi adalah interaksi terpisah, gunakan panah kiri dan kanan untuk fungsi perluasan/penciutan. Untuk kontrol yang berorientasi, kaitkan tombol arah dengan orientasi visual kontrol.

Perilaku kunci kustom biasanya diimplementasikan dengan menimpa OnKeyDown dan OnKeyUp.

Contoh status visual untuk indikator fokus

Kontrol kustom yang dapat difokuskan harus mengekspos indikator fokus visual yang jelas. Pola templat umum menggunakan overlay Persegi panjang yang mulai tersembunyi melalui Visibilitas dan muncul saat fokus masuk.

Kontrol XAML bawaan sudah menyediakan indikator fokus. Tampilan yang tepat dapat bervariasi dengan pengaturan tema, termasuk mode kontras tinggi. Jika Anda meretemplate kontrol, pertahankan perilaku visibilitas fokus yang setara.

Contoh berikut diadaptasi dari templat Tombol default.

<ControlTemplate TargetType="Button">
...
    <Rectangle
      x:Name="FocusVisualWhite"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="1.5"/>
    <Rectangle
      x:Name="FocusVisualBlack"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="0.5"/>
...
</ControlTemplate>

Untuk mengalihkan visibilitas indikator fokus, gunakan VisualStateManager dan VisualStateManager.VisualStateGroups pada akar templat.

<ControlTemplate TargetType="Button">
  <Grid>
    <VisualStateManager.VisualStateGroups>
      <!--other visual state groups here-->
      <VisualStateGroup x:Name="FocusStates">
        <VisualState x:Name="Focused">
          <Storyboard>
            <DoubleAnimation
              Storyboard.TargetName="FocusVisualWhite"
              Storyboard.TargetProperty="Opacity"
              To="1" Duration="0"/>
            <DoubleAnimation
              Storyboard.TargetName="FocusVisualBlack"
              Storyboard.TargetProperty="Opacity"
              To="1" Duration="0"/>
          </Storyboard>
        </VisualState>
        <VisualState x:Name="Unfocused" />
        <VisualState x:Name="PointerFocused" />
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!--composition is here-->
  </Grid>
</ControlTemplate>

Hanya satu status dalam grup ini yang secara eksplisit memodifikasi visual fokus. Status lain dapat tetap kosong karena transisi di dalam VisualStateGroup yang sama membatalkan animasi status sebelumnya. Peristiwa fokus seperti GotFocus, dikombinasikan dengan GoToState, biasanya mendorong transisi ini.

Aksesibilitas papan ketik dan perangkat tanpa papan ketik perangkat keras

Beberapa perangkat mengandalkan Panel Input Lunak (SIP) alih-alih keyboard perangkat keras. Pembaca layar dapat mendeteksi bahwa pengguna memindai kunci dan mengumumkan eksplorasi kunci SIP pengguna, dan banyak konsep aksesibilitas keyboard masih berlaku melalui gerakan yang setara.

Misalnya, bahkan tanpa tombol Tab fisik, Narator mendukung gerakan yang berfungsi seperti traversal tombol Tab. Itu berarti urutan tab koheren masih penting. Narator juga menyediakan gestur yang setara untuk navigasi arah dalam kontrol kompleks (lihat Perintah keyboard Narator dan gerakan sentuh).

Contoh

Ikon Galeri WinUI 3 Aplikasi Galeri WinUI 3 mencakup contoh interaktif kontrol dan fitur WinUI. Dapatkan aplikasi dari Microsoft Store atau telusuri kode sumber pada GitHub.