Windows 長期以來支持數位筆,讓使用者能以自然、直接的方式與裝置互動,並透過數位墨水豐富的書寫與繪畫體驗來表達創意。
隨著 Windows 11 的推出,一項新功能將讓數位筆的使用體驗更加自然且引人入勝:當使用支援「觸覺回饋」的筆時,使用者能真實感受到筆與應用程式使用者介面(UI)的觸覺互動。
備註
在提及這項新功能時,開發者 API 及相關文件中普遍使用「觸覺」,而「觸感」則是用戶在 Windows 設定中設定回饋偏好時所使用的友善名稱。
Windows 11 支援的觸覺回饋體驗包括 墨線回饋 與 互動回饋:
- 描線回饋透過筆接觸螢幕時持續震動,模擬各種書寫或繪畫工具(如鋼筆、麥克筆、鉛筆、螢光筆等)的觸感。 預設情況下, Windows Ink 平台 支援所有繪圖工具的觸覺回饋(本主題將介紹如何在 Windows Ink 支援之外提供自訂的墨線解決方案)。
- 互動回饋是直接基於關鍵使用者操作而來的回饋,例如當滑鼠停留在按鈕上或點擊時的反應,完成動作時的回應,或是用以吸引使用者的注意。
通常,要完全支援觸覺回饋,需要五個步驟:
- 偵測筆輸入。
- 確認目前的筆和裝置是否支援觸覺回饋,如果支援,則支援哪些觸覺回饋功能。
- 決定要發送的觸覺回饋訊號。
- 傳送觸覺回饋。
- 停止觸覺回饋
偵測筆輸入
要偵測並隔離筆輸入,你必須先註冊 PointerEntered 事件,然後檢查 PointerDeviceType 是否是 筆。
以下程式碼說明如何在 PointerEntered 事件中檢查指標裝置類型。 在這個例子中,如果輸入不是來自筆,我們就直接從事件處理器回傳。 否則,我們會檢查觸控筆的功能並設定觸覺回饋。
private void InputObserver_PointerEntered(object sender, PointerRoutedEventArgs e)
{
...
// If the current Pointer device is not a pen, exit.
if (e.Pointer.PointerDeviceType != PointerDeviceType.Pen)
{
return;
}
...
}
確定對觸覺回饋的支持
並非所有筆和數位化器都支援觸覺回饋,而支援的筆也不一定支援本主題中描述的所有觸覺回饋功能。 因此,程式化確認主動筆支援哪些功能非常重要。
在前述範例的延續中,我們展示了如何檢查主動筆是否支援觸覺回饋。
我們首先嘗試從目前的 PointerID 中擷取一個 PenDevice 物件。 若無法取得 PenDevice ,我們只需從事件處理程序返回。
如果取得 PenDevice ,我們會測試它是否支援 SimpleHapticsController 屬性。 如果沒有,我們就直接從事件處理器返回。
// Attempt to retrieve the PenDevice from the current PointerId.
penDevice = PenDevice.GetFromPointerId(e.Pointer.PointerId);
// If a PenDevice cannot be retrieved based on the PointerId, it does not support
// advanced pen features, such as haptic feedback.
if (penDevice == null)
{
return;
}
// Check to see if the current PenDevice supports haptic feedback by seeing if it
// has a SimpleHapticsController.
hapticsController = penDevice.SimpleHapticsController;
if (hapticsController == null)
{
return;
}
前述範例中取得的 SimpleHapticsController 在後續範例中用於查詢觸覺能力及發送/停止觸覺回饋。
備註
如果你正在使用 Windows App SDK 預覽版 1.0 來建置應用程式,可以使用 PenDevice 互操作 (PenDeviceInterop.FromPointerPoint(PointerPoint))來存取系統中的 PenDevice。
private void InputObserver_PointerEntered(PointerInputObserver sender, PointerEventArgs args)
{
var penDevice = PenDeviceInterop.PenDeviceFromPointerPoint(args.CurrentPoint);
}
以下章節說明觸覺筆必須支援的回饋功能,以及可選的功能。 通常可以將必要的觸覺回饋類型用作備用方案,而不是選用功能。
墨跡波形
當筆不斷接觸螢幕時,描線波形持續運行,模擬不同書寫或繪圖工具的手感。
| 特徵 / 功能 | Description | 必修/選修 |
|---|---|---|
| Ink連續波形 | 模擬用實體原子筆描墨的手感。 當觸覺筆不支援墨線波形時,這是預設的備用方式。 | 為必填項目 |
| 刷子連續波形 | 使用者選擇筆刷作為墨線工具時,會有持續的觸覺訊號。 | 可選 |
| ChiselMarker 連續波形 | 使用者選擇鑿子筆/螢光筆作為描線工具時,會有持續的觸覺訊號。 | 可選 |
| 橡皮擦連續波形 | 使用者選擇橡皮擦作為描線工具時,會有持續的觸覺訊號。 | 可選 |
| Galaxy連續波形 (HID 文件與實作指南將此波形稱為 SparkleContinuous) |
針對特殊墨水工具(如多色畫筆)提供連續觸覺訊號。 | 可選 |
| Marker連續波形 | 使用者選擇標記作為描線工具時,會產生持續的觸覺訊號。 | 可選 |
| 鉛筆連續波形 | 使用者選擇鉛筆作為描線工具時,會有持續的觸覺訊號。 | 可選 |
交互作用波形
互動波形通常很短(下表有例外),是即時產生的直接反饋波形,用來確認關鍵動作,例如滑鼠移至或點擊按鈕、回應動作完成,或吸引使用者注意。
| 特徵 / 功能 | Description | 必修/選修 |
|---|---|---|
| 點擊波形圖 | 一個短暫的「喀嚓」回饋。 當應用程式選擇的互動波形未被觸覺筆支援時,這是預設的備用方式。 | 為必填項目 |
| 誤差波形 | 強烈的訊號提醒使用者動作失敗或發生錯誤。 | 可選 |
| 懸浮波形 | 表示使用者已開始將滑鼠移至互動式 UI 元素上。 | 可選 |
| 按壓波形 | 表示使用者在增量動作中按下互動式 UI 元素時(參見 Release)。 | 可選 |
| 釋放波形 | 表示使用者何時以增量動作釋出互動式 UI 元素(見 Press)。 | 可選 |
| 成功波形 | 強訊號提醒使用者動作成功。 | 可選 |
| Buzz 連續波形 | 持續的嗡嗡聲。 | 可選 |
| 隆隆連續波形 | 持續的隆隆震動感。 | 可選 |
觸覺回饋個性化設定
部分觸覺筆可支援以下客製化功能。
| 特徵 / 功能 | Description | 必修/選修 |
|---|---|---|
| 強烈 | 設定觸覺訊號的強度。 | 可選 |
| 出場次數 | 重複一個觸覺訊號指定次數。 | 可選 |
| 重播暫停時間 | 設定每次重複播放觸覺訊號之間的時間。 | 可選 |
| 遊玩時長 | 設定觸覺訊號播放的時間間隔。 | 可選 |
檢查是否有支援自訂設定
要檢查強度、播放次數、重播暫停間隔及播放時長的支援,請使用 SimpleHapticsController 的以下屬性:
發送和停止數位書寫觸覺回饋
使用 SimpleHapticsController 物件的 SendHapticFeedback 方法,將描線波形傳遞給使用者的筆。 此方法支援輸入波形,或同時輸入波形與自訂強度值。(參見自訂觸覺反饋)。
呼叫 SendHapticFeedback,輸入 一個描墨波形 ,設定筆尖一碰到螢幕就開始播放該波形。 波形會持續播放,直到筆被抬起或呼叫 停止回饋(StopFeedback),以先發生者為準。 我們建議你在 PointerEntered 事件處理器中,以便在你想播放觸覺反饋的元素上執行此操作。 例如,一個有自訂描線實作的應用程式會在其描線畫布的 PointerEntered 方法中完成這件事。
要取得所需的描線波形,必須遍歷 SimpleHapticsController 的 SupportedFeedback 集合,確保該波形由主動筆支援。
如果不支援,你可以選擇完全不播放任何內容,或者回退到 InkContinuous 波形,因為那是保證支援的。
在以下範例中,我們嘗試傳送 BrushContinuous 波形(但若不支援 BrushContinuous,則回退回 InkContinuous)。
SimpleHapticsControllerFeedback currentWaveform;
// Attempt to set the currentWaveform to BrushContinuous.
foreach (var waveform in hapticsController.SupportedFeedback)
{
if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.BrushContinuous)
{
currentWaveform = waveform;
}
}
// If currentWaveform is null, it was not in the SupportedFeedback collection, so instead set
// the waveform to InkContinuous.
if (currentWaveform == null)
{
foreach (var waveform in hapticsController.SupportedFeedback)
{
if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.InkContinuous)
{
currentWaveform = waveform;
}
}
}
// Send the currentWaveform
hapticsController.SendHapticFeedback(currentWaveform);
當相關指標離開你註冊的觸覺回饋元素時,也要停止觸覺回饋。 否則,波形會繼續嘗試在主動筆上播放。
備註
有些筆可能會在離開螢幕範圍時自動停止觸覺功能。 然而,並非所有筆都必須如此,因此應用程式應明確停止觸覺回饋,如本文所述。
要停止元素的觸覺反饋,請在與您註冊發送觸覺訊號的 PointerEntered 處理器相同的元素上註冊 PointerExited 事件。 在退出事件處理器中,呼叫 StopFeedback ,如圖所示。
hapticsController.StopFeedback();
發送與停止互動回饋
發送互動回饋與發送墨線回饋相當相似。
使用 SimpleHapticsController 物件的 SendHapticFeedback 方法,將互動波形傳遞給使用者的筆。 此方法支援輸入波形,或同時輸入波形與自訂強度值。(參見自訂觸覺反饋)。
呼叫 SendHapticFeedback,輸入一個 描墨波形 ,讓筆能根據應用程式內的互動立即開始播放該波形(而不是筆尖觸屏時才開始播放)。
使用任何非連續的互動波形時,無需對應的 停止反饋 呼叫。 你仍然需要呼叫 StopFeedback 來取得連續的互動波形。
備註
在播放描線波形時發送互動波形會暫時中斷該波形。 當互動波形停止時,墨線波形會恢復。
要取得所需的互動波形,你必須遍歷 SimpleHapticsController 的 SupportedFeedback 集合,確保該集合由主動筆支援。
如果不支援,你可以選擇完全不播放任何東西,或是退回 點擊波形 ,因為那是保證支援的。
在以下範例中,我們嘗試傳送 錯誤 波形(但若不支援 錯誤,則回退至 點擊 波形)。
SimpleHapticsControllerFeedback currentWaveform;
// Attempt to set the currentWaveform to BrushContinuous.
foreach (var waveform in hapticsController.SupportedFeedback)
{
if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Error)
{
currentWaveform = waveform;
}
}
// If currentWaveform is null, it was not in the SupportedFeedback collection, so instead set
// the waveform to Click.
if (currentWaveform == null)
{
foreach (var waveform in hapticsController.SupportedFeedback)
{
if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Click)
{
currentWaveform = waveform;
}
}
}
// Send the currentWaveform.
hapticsController.SendHapticFeedback(currentWaveform);
自訂觸覺回饋
有三種方式可以自訂觸覺回饋。 第一類有墨線和互動回饋支持,第二和第三種則僅靠互動回饋支持。
調整反饋強度相對於系統最大強度設定。 為此,你必須先檢查 SimpleHapticsController 是否支援設定強度,然後呼叫 SendHapticFeedback 提供所需的
Intensity數值。if (hapticsController.IsIntensitySupported) { foreach (var waveform in hapticsController.SupportedFeedback) { if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Click) { double intensity = 0.75; hapticsController.SendHapticFeedback(waveform, intensity); } } }重複指定次數的觸覺訊號。 為此,你必須先確認 SimpleHapticsController 是否支援設定強度,然後呼叫 SendHapticFeedbackForPlayCount 並設定所需的計數值。 你也可以設定強度和重播暫停間隔。
備註
若 SimpleHapticsController 不支援設定強度或重播暫停間隔,則所提供的數值將被忽略。
if (hapticsController.IsPlayCountSupported && hapticsController.IsIntensitySupported && hapticsController.IsReplayPauseIntervalSupported) { foreach (var waveform in hapticsController.SupportedFeedback) { if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.Click) { double intensity = 0.75; int playCount = 3; System.TimeSpan pauseDuration = new System.TimeSpan(1000000); hapticsController.SendHapticFeedbackForPlayCount(currentWaveform, intensity, playCount, pauseDuration); } } }設定觸覺訊號的持續時間。 為此,你必須先確認 SimpleHapticsController 是否支援設定播放時長,然後呼叫 SendHapticFeedbackForDuration ,並設定所需的時間間隔值。 你也可以設定強度。
備註
如果 SimpleHapticsController 不支援設定強度,所提供的數值將被忽略。
if (hapticsController.IsPlayDurationSupported && hapticsController.IsIntensitySupported) { foreach (var waveform in hapticsController.SupportedFeedback) { if (waveform.Waveform == KnownSimpleHapticsControllerWaveforms.RumbleContinuous) { double intensity = 0.75; System.TimeSpan playDuration = new System.TimeSpan(5000000); hapticsController.SendHapticFeedbackForDuration(currentWaveform, intensity, playDuration); } } }
範例
以下功能的操作範例請參考 筆觸覺範例 :
- 從筆輸入取得 SimpleHapticsController :從 PointerId 到 PenDevice 再到 SimpleHapticsController (需要同時支援觸覺功能的筆和支援該筆的裝置)。
- 檢查筆觸覺功能: SimpleHapticsController 會顯示筆硬體功能屬性,包括 IsIntensitySupported、 IsPlayCountSupported、 SupportedFeedback 等。
- 開始與停止觸覺回饋:適當使用 SendHapticFeedback 和 StopFeedback 方法。
- 觸發觸覺反饋:同時提供 書寫回饋 和 互動回饋。