在Windows应用中实现触觉反馈

本文介绍如何使用 InputHapticsManager API 将触觉反馈添加到Windows应用,包括常见交互模式的代码示例。

有关何时和为何使用触觉的设计指南,请参阅 触觉设计指南

支持的设备

触觉在鼠标、触摸板和笔等输入设备上受支持。 可用性因型号和制造商而异。 在调用触觉 API 之前,请始终在运行时检查支持(请参阅以下 检查支持 )。

Requirements

要求 详细信息
Namespace Windows.Devices.Haptics
最低 OS Windows 11 SDK 10.0.28000.1721(2026 年 3 月)
对齐 / 碰撞 / 阶梯 / 渐增波形 SDK 10.0.28000.1839 (2026 年 4 月)
API 协定 UniversalApiContract 版本 19.0

若要面向早期操作系统版本,请使用 ApiInformation.IsTypePresent 保护所有调用(请参阅下面的代码)。

检查是否支持

请始终验证 API 是否可用,并且触觉设备在使用前是否存在。 旧版 OS 上不存在该 API,并非所有输入设备都支持触觉。

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

触发一个波形

在 UI 线程上调用 InputHapticsManager.GetForCurrentThread() 以获取一个与当前线程的输入焦点关联的管理器实例。 自动处理设备检测和路由 - 无需自行枚举设备。

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

从 UI 线程(或拥有输入焦点的线程)调用 GetForCurrentThread()。 从后台线程调用它不会将反馈路由到正确的设备。

停止播放

拖动或交互结束时调用 TryStopFeedback 以停止任何正在进行的触觉播放。

using Windows.Devices.Haptics;

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

实现示例

对象对齐方式

对齐指南在设计工具、演示文稿编辑器和图表应用中很常见。 触觉反馈提供了第二种感知渠道,让用户能够感知到对象何时吸附到位,从而减少了通过放大来目视确认是否对齐的需要。

何时触发: 以对齐参考线的出现作为触发信号。 当吸附逻辑显示参考线时,触发触觉反馈。 如果没有出现任何导引,请不要开火。 这可使触觉事件紧密耦合到可见的系统反馈。

避免重复: 形状可以同时对齐多个参考线(例如左边缘和上边缘)。 将此视为单个交互 - 跟踪活动指南,仅在 出现新 指南时触发。

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

触觉通过将反馈定位到有意义的位置来改善滑块交互。 始终将反馈与用户可以理解的可见标记(刻度线、命名值或范围边界)联系在一起。

何时触发: 当拇指滑过每个刻度线时,触发触觉反馈。 避免在滴答声之间持续提供反馈,这样会让人觉得分心。

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

优化体验: 根据滑块位置缩放触觉强度,以帮助用户感知其范围内 的位置 。 使用 TrySendHapticWaveformForPlayCount,它接受从 0.01.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;
}

拖动交互和意图检测

在拖动期间,对象可以跨越许多对齐边界-页面中心、参考线和其他对象。 每次越过边界时都触发触觉反馈,可能会让用户应接不暇,尤其是在用户快速移动、只是重新定位而非追求精确操作时。

仅当用户尝试故意对齐时,使用 意向检测 才会触发反馈,而不仅仅是传递。

方法 1:速度过滤器

当光标快速移动时,禁止触觉,保留反馈,以便进行较慢、更刻意的移动。

  • 稳定信号。 避免使用原始游标增量,这可能会在输入类型、DPI 设置和显示配置之间产生干扰。 规范化和平滑信号。
  • 请仔细选择阈值。 跨不同设备、输入类型、显示缩放和多显示设置进行验证。

方法 2:定时器消抖

当对象进入触发器区域时,启动短计时器(50 毫秒是合理的起点)。 如果物体在计时结束时仍停留在该区域内,则将其视为有意为之,并触发触觉反馈。 如果对象在计时器触发前继续移动,请取消反馈。

  • 更易于实现,而且与速度滤波相比,往往能表现出更稳定的行为。
  • 50 毫秒的延迟足够长,可以区分故意对齐方式与快速传递,同时仍低于明显延迟的阈值。
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();
}

在两者之间选择

速度筛选器 计时器消抖
工作原理 响应式——实时测量运动 预测性——短暂等待以确认用户意图
感觉 可带来更强的即时感 略有延迟,但更一致
调优工作量 更高 - 需要仔细校准 较低 - 单个延迟值通常足够
推荐用于 需要高度响应反馈的应用 大多数应用;良好的默认起点