Implementar feedback háptico nas aplicações do Windows

Este artigo explica como adicionar feedback háptico à sua aplicação Windows usando a API InputHapticsManager, incluindo exemplos de código para padrões comuns de interação.

Para orientações de design sobre quando e porquê usar háptica, consulte as diretrizes de design da Haptics.

Dispositivos suportados

Os hápticos são suportados em dispositivos de entrada como ratos, touchpads e canetas. A disponibilidade varia consoante o modelo e o fabricante. Verifique sempre o suporte em tempo de execução antes de chamar APIs hápticas (veja Verificar suporte abaixo).

Requirements

Requirement Detalhes
Namespace Windows.Devices.Haptics
OS mínimo Windows 11, SDK 10.0.28000.1721 (março de 2026)
Alinhar / Colidir / Avançar / Aumentar formas de onda SDK 10.0.28000.1839 (abril 2026)
Contrato API UniversalApiContract Versão 19.0

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

Verifique se há apoio

Verifique sempre que a API está disponível e que existe um dispositivo háptico antes de ser utilizado. A API não está presente nas versões antigas do sistema operativo, e nem todos os dispositivos de entrada suportam háptica.

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() no thread da interface do utilizador para obter uma instância do gestor associada ao foco de entrada do thread atual. A deteção e o encaminhamento de dispositivos são tratados automaticamente — não precisa de enumerar os dispositivos por si próprio.

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

Important

Chama GetForCurrentThread() a partir do thread da interface (ou do thread que detém o foco de entrada). Chamá-lo a partir de um thread em segundo plano não vai encaminhar feedback para o dispositivo correto.

Parar a reprodução

Chame TryStopFeedback quando um arrasto ou uma interação terminar para parar qualquer reprodução háptica em curso.

using Windows.Devices.Haptics;

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

Exemplo de Implementação

Alinhamento de objetos

Guias de alinhamento são comuns em ferramentas de design, editores de apresentações e aplicações de diagramas. O feedback háptico adiciona um segundo canal para que os utilizadores possam sentir quando os objetos encaixam no lugar — 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 do snap mostrar um guia, dispara o háptico. Se não aparecer nenhum guia, não dispares. Isto mantém os eventos hápticos fortemente ligados ao feedback visível do sistema.

Evite duplicados: Uma forma pode alinhar-se com múltiplas guias simultaneamente (por exemplo, borda esquerda e borda superior). Trate isto como uma única interação — acompanhe os guias ativos e só dispare quando aparecer um novo guia.

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 háptica melhora as interações dos sliders ao ancorar o feedback em posições significativas. Associe sempre o feedback a marcadores visíveis que o utilizador consiga compreender—marcas, valores nomeados ou limites de intervalo.

Quando acionar: Acione o feedback háptico à medida que o polegar passa por cada marca. Evite o feedback contínuo entre os tiques, que pode ser distrativo.

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

Refinar a experiência: Escala a intensidade háptica com base na posição do deslizador para ajudar os utilizadores a perceber onde se encontram dentro do intervalo. Use TrySendHapticWaveformForPlayCount, que aceita um valor de intensidade explícito de 0.0 para 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 arrasto e deteção de intenção

Durante um arrasto, um objeto pode atravessar muitos limites de alinhamento — centro de página, guias, outros objetos. Acionar feedback háptico sempre que há um cruzamento pode sobrecarregar os utilizadores, especialmente durante movimentos rápidos, quando estão a reposicionar-se em vez de tentarem ser precisos.

Utilize a deteção de intenção para acionar o feedback apenas quando o utilizador está deliberadamente a tentar alinhar-se, e não apenas de passagem.

Abordagem 1: Filtro de velocidade

Suprime a háptica quando o cursor se move rapidamente, reservando o feedback para movimentos mais lentos e deliberados.

  • Estabiliza o sinal. Evite usar deltas de cursor brutos, que podem ser ruidosos em diferentes tipos de entrada, definições de DPI e configurações de visualização. Normaliza e suaviza o sinal.
  • Escolha cuidadosamente um limiar. Valide entre diferentes dispositivos, tipos de entrada, escalas de ecrã e configurações multi-ecrã.

Abordagem 2: Deboque do temporizador

Quando um objeto entra numa zona de disparo, inicie um temporizador curto (50 ms é um ponto de partida razoável). Se o objeto permanecer na zona quando o temporizador chegar ao fim, considere-o intencional e ative o feedback háptico. Se o objeto avançar antes do temporizador disparar, suprima o feedback.

  • Mais simples de implementar e tende a produzir um comportamento mais estável do que o filtro de velocidade.
  • Um atraso de 50 ms é suficiente para distinguir o alinhamento deliberado de uma passagem rápida, mantendo-se abaixo do limiar de latência notória.
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();
}

Escolher entre os dois

Filtro de velocidade Ressalto do temporizador
Como funciona Reativo — mede o movimento em tempo real Preditivo—espera brevemente para confirmar a intenção
Sentir Pode parecer mais imediato Ligeiramente atrasado, mas mais consistente
Esforço de afinação Mais alto — requer calibração cuidadosa Menor — um único valor de atraso é geralmente suficiente
Recomendado para Aplicações que requerem feedback altamente responsivo A maioria das aplicações; Bom ponto de partida padrão