Implementar comentários hápticos em aplicativos Windows

Este artigo explica como adicionar comentários hápticos ao seu aplicativo Windows usando a API InputHapticsManager, incluindo exemplos de código para padrões de interação comuns.

Para obter diretrizes de design sobre quando e por que usar hápticos, consulte as diretrizes de design haptics.

Dispositivos com suporte

Há suporte para hápticos em dispositivos de entrada, como mouses, touchpads e canetas. A disponibilidade varia de acordo com o modelo e o fabricante. Sempre verifique se há suporte no runtime antes de chamar APIs hápticas (consulte Verificar se há suporte abaixo).

Requirements

Requisito Detalhes
Namespace Windows.Devices.Haptics
Sistema operacional mínimo Windows 11, SDK 10.0.28000.1721 (março de 2026)
Alinhar/Colidir/Etapa/Aumentar formas de onda SDK 10.0.28000.1839 (abril de 2026)
Contrato de API UniversalApiContract versão 19.0

Para direcionar versões anteriores do sistema operacional, use ApiInformation.IsTypePresent para proteger todas as chamadas (consulte o código abaixo).

Procurar suporte

Sempre verifique se a API está disponível e se um dispositivo háptico está presente antes do uso. A API não está presente em versões mais antigas do sistema operacional e nem todos os dispositivos de entrada dão suporte a hápticos.

using Windows.Devices.Haptics;
using Windows.Foundation.Metadata;

// Guard against older OS versions where the API is absent.
bool apiPresent = ApiInformation.IsTypePresent("Windows.Devices.Haptics.InputHapticsManager");

// Check that a supported haptic device is connected.
bool supported = apiPresent && InputHapticsManager.IsSupported();

Acionar uma forma de onda

Chame InputHapticsManager.GetForCurrentThread() na thread da interface do usuário para obter uma instância do gerenciador no escopo do foco de entrada da thread atual. A detecção e o roteamento do dispositivo são tratados automaticamente– você não precisa enumerar dispositivos por conta própria.

using Windows.Devices.Haptics;

if (supported)
{
    var mgr = InputHapticsManager.GetForCurrentThread();

    // The second parameter is a fallback waveform used if the first is
    // unsupported. Passing 0 lets the system choose a device-appropriate
    // fallback. TrySendHapticWaveform returns false if neither waveform is
    // supported; this is a non-fatal condition.
    bool sent = mgr.TrySendHapticWaveform(
        KnownSimpleHapticsControllerWaveforms.Align,
        0);
}

Importante

Chame GetForCurrentThread() do thread de interface do usuário (ou o thread que possui o foco de entrada). Chamá-lo a partir de uma thread em segundo plano não encaminhará o feedback para o dispositivo correto.

Parar a reprodução

Chame TryStopFeedback quando um arraste ou uma interação terminar para interromper qualquer reprodução háptica em andamento.

using Windows.Devices.Haptics;

if (supported)
{
    InputHapticsManager
        .GetForCurrentThread()
        .TryStopFeedback();
}

Exemplo de implementação

Alinhamento do objeto

Guias de alinhamento são comuns em ferramentas de design, editores de apresentação e aplicativos de diagramação. Os comentários hápticos adicionam um segundo canal para que os usuários possam sentir quando os objetos se ajustarem — reduzindo a necessidade de ampliar para confirmar visualmente o alinhamento.

Quando disparar: Use a aparência do guia de alinhamento como gatilho. Quando a lógica de encaixe mostrar um guia, ative o feedback tátil. Se nenhum guia for exibido, não dispare. Isso mantém os eventos hápticos estreitamente vinculados ao feedback visual do sistema.

Evite duplicatas: Uma forma pode se alinhar a vários guias simultaneamente (por exemplo, borda esquerda e borda superior). Trate isso como uma única interação: acompanhe os guias ativos e dispare somente quando um novo guia aparecer.

using Windows.Devices.Haptics;

private readonly HashSet<int> _activeGuides = new();

// Call this after computing which alignment guides are currently visible.
void OnGuidesUpdated(IEnumerable<int> currentGuideIds)
{
    var currentGuides = currentGuideIds.ToHashSet();

    bool hasNewGuide = currentGuides.Except(_activeGuides).Any();

    // Update the tracked set in place (field is readonly).
    _activeGuides.Clear();
    _activeGuides.UnionWith(currentGuides);

    if (hasNewGuide && supported)
    {
        InputHapticsManager.GetForCurrentThread()
            .TrySendHapticWaveform(
                KnownSimpleHapticsControllerWaveforms.Align,
                0);
    }
}

Sliders

A resposta tátil melhora as interações com controles deslizantes ao associar o feedback a posições significativas. Sempre vincule comentários a marcadores visíveis que o usuário pode entender: marcas de escala, valores nomeados ou limites de intervalo.

Quando acionar: Acione o feedback tátil à medida que o polegar cruza cada marca de graduação. Evite feedback contínuo entre um tique sonoro e outro, pois isso pode distrair.

using Windows.Devices.Haptics;

double _previousValue;
const double TickInterval = 25.0;

void OnSliderValueChanged(double newValue)
{
    int previousTick = (int)(_previousValue / TickInterval);
    int currentTick  = (int)(newValue       / TickInterval);

    if (currentTick != previousTick && supported)
    {
        InputHapticsManager.GetForCurrentThread()
            .TrySendHapticWaveform(
                KnownSimpleHapticsControllerWaveforms.Step,
                0);
    }

    _previousValue = newValue;
}

Refinando a experiência: Dimensione a intensidade háptica com base na posição do controle deslizante para ajudar os usuários a sentir onde estão dentro do intervalo. Use TrySendHapticWaveformForPlayCount, que aceita um valor de intensidade explícito de 0.0 até 1.0.

void OnSliderValueChangedWithIntensity(double newValue, double maxValue)
{
    int previousTick = (int)(_previousValue / TickInterval);
    int currentTick  = (int)(newValue       / TickInterval);

    if (currentTick != previousTick && supported)
    {
        double intensity = newValue / maxValue; // Scale 0.0–1.0

        InputHapticsManager.GetForCurrentThread()
            .TrySendHapticWaveformForPlayCount(
                KnownSimpleHapticsControllerWaveforms.Step,
                0,          // fallback waveform
                intensity,
                1,          // playCount
                TimeSpan.Zero);
    }

    _previousValue = newValue;
}

Interações de arrastar e detecção de intenção

Durante um arraste, um objeto pode cruzar muitos limites de alinhamento — centro de páginas, guias, outros objetos. Acionar feedback tátil a cada cruzamento pode sobrecarregar os usuários, especialmente durante movimentos rápidos, quando estão apenas reposicionando em vez de tentar ser precisos.

Use detecção de intenção para acionar o feedback somente quando o usuário estiver tentando alinhar deliberadamente, e não apenas de passagem.

Abordagem 1: Filtro de velocidade

Suprima o feedback tátil quando o cursor estiver se movendo rapidamente, reservando-o para movimentos mais lentos e deliberados.

  • Estabilize o sinal. Evite usar deltas de cursor brutos, que podem ser barulhentos entre tipos de entrada, configurações de DPI e configurações de exibição. Normalize e alise o sinal.
  • Escolha um limite com cuidado. Valide em diferentes dispositivos, tipos de entrada, escalas de exibição e configurações com vários monitores.

Abordagem 2: Temporizador de debounce

Quando um objeto entra em uma zona de gatilho, inicie um temporizador curto (50 ms é um ponto de partida razoável). Se o objeto permanecer na zona quando o temporizador terminar, considere-o intencional e acione o feedback háptico. Se o objeto seguir em frente antes que o temporizador dispare, suprima o feedback.

  • Mais simples de implementar e tende a produzir um comportamento mais estável do que a filtragem de velocidade.
  • Um atraso de 50 ms é longo o suficiente para distinguir o alinhamento deliberado de um passe rápido, mantendo-se abaixo do limite de latência perceptível.
using System;
using Microsoft.UI.Xaml;
using Windows.Devices.Haptics;

private DispatcherTimer? _alignTimer;

void OnObjectEnteredAlignmentZone()
{
    _alignTimer?.Stop();
    _alignTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(50) };
    _alignTimer.Tick += (_, _) =>
    {
        _alignTimer.Stop();
        if (supported)
        {
            InputHapticsManager.GetForCurrentThread()
                .TrySendHapticWaveform(
                    KnownSimpleHapticsControllerWaveforms.Align,
                    0);
        }
    };
    _alignTimer.Start();
}

void OnObjectLeftAlignmentZone()
{
    _alignTimer?.Stop();
}

Escolhendo entre os dois

Filtro de velocidade Debounce do temporizador
Como funciona Reativo – mede o movimento em tempo real Preditivo – aguarda brevemente para confirmar a intenção
Sentir Pode parecer mais imediato Um pouco atrasado, mas mais consistente
Esforço de ajuste Mais alto – requer uma calibragem cuidadosa Menor – um único valor de atraso geralmente é suficiente
Recomendado para Aplicativos que exigem comentários altamente responsivos A maioria dos aplicativos; bom ponto de partida padrão