この記事では、InputHapticsManager API を使用してWindows アプリに触覚フィードバックを追加する方法について説明します。これには、一般的な相互作用パターンのコード例が含まれます。
触覚を使用するタイミングと理由に関する設計ガイダンスについては、 触覚設計ガイドラインを参照してください。
サポートされているデバイス
触覚は、マウス、タッチパッド、ペンなどの入力デバイスでサポートされています。 可用性は、モデルと製造元によって異なります。 触覚 API を呼び出す前に、必ず実行時にサポートを確認してください (以下 のサポートの確認を 参照してください)。
Requirements
| Requirement | 詳細情報 |
|---|---|
| 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 |
以前の OS バージョンを対象にするには、 ApiInformation.IsTypePresent を使用してすべての呼び出しを保護します (以下のコードを参照)。
サポートを確認する
使用する前に、API が使用可能であり、触覚デバイスが存在することを常に確認してください。 API は古い OS バージョンには存在せず、すべての入力デバイスが触覚をサポートしているわけではありません。
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();
}
実装の例
オブジェクトの配置
配置ガイドは、デザイン ツール、プレゼンテーション エディター、および図作成アプリでよく使用されます。 触覚フィードバックによって 2 つ目のチャネルが追加され、オブジェクトが所定の位置にスナップしたときにユーザーが 感じ ることができるため、配置を視覚的に確認するために拡大する必要が減ります。
起動するタイミング: 配置ガイドの外観をトリガーとして使用します。 スナップ ロジックにガイドが表示されたら、触覚を起動します。 ガイドが表示されない場合は、起動しないでください。 これにより、触覚イベントが、可視のシステム フィードバックと密接に結び付けられます。
重複を回避する: 図形は複数のガイド (左端や上端など) に同時に配置できます。 これは 1 つの操作として扱います。アクティブなガイドを追跡し、 新しい ガイドが表示されたときにのみ起動します。
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.0から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;
}
ドラッグ操作と意図検出
ドラッグ中、オブジェクトは、ページの中心、ガイド、その他のオブジェクトなど、多数の配置境界を越えることができます。 境界をまたぐたびに触覚フィードバックを発生させると、ユーザーの負担になる可能性があります。特に、正確な操作をしようとしているのではなく、位置を調整するためにすばやく動かしているときはそうです。
意図検出を使用して、ユーザーが通過するだけでなく、意図的に調整しようとしている場合にのみフィードバックを送信します。
方法 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();
}
2 つから選択する
| 速度フィルター | タイマーデバウンス | |
|---|---|---|
| どのように機能するのか | リアクティブ— リアルタイムでの移動を測定 | 予測 - 意図を確認するために少し待ちます |
| 感じる | より即時に感じられます | 少し遅れているが、一貫性が高い |
| チューニング作業 | より高い— 慎重なキャリブレーションが必要 | 低 —通常、1 つの遅延値で十分です |
| 推奨対象 | 応答性の高いフィードバックを必要とするアプリ | ほとんどのアプリ。適切な既定の開始点 |
関連資料
- 触覚設計ガイドライン
- InputHapticsManager API リファレンス
- KnownSimpleHapticsControllerWaveforms
- 触覚の設計と実装 (microsoft.design)
- 入力入門
- タッチ操作
Windows developer