手寫筆互動和觸覺 (觸碰) 回饋
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 Preview 1.0 建立應用程式,則可以使用 PenDevice 互通 (PenDeviceInterop.FromPointerPoint(PointerPoint)) 存取系統 PenDevice。
private void InputObserver_PointerEntered(PointerInputObserver sender, PointerEventArgs args)
{
var penDevice = PenDeviceInterop.PenDeviceFromPointerPoint(args.CurrentPoint);
}
以下部分描述觸覺筆必須支援的回饋功能以及可選的回饋功能。 必要的觸覺反饋類型通常可用來作為後援,而不是選擇性功能。
筆跡超聲波
筆跡超聲波會在筆與螢幕接觸時持續播放,並嘗試模擬各種書寫或繪圖工具的感覺。
功能 | 描述 | 必要條件 / 選擇性 |
---|---|---|
InkContinous 電壓 | 模擬使用實體球點筆跡的感覺。 這是觸覺筆不支援筆跡電壓時的預設後援。 | 必要 |
BrushContinuous 波狀 | 當使用者選取筆刷做為筆跡工具時,連續觸覺訊號。 | 選擇性 |
ChiselMarkerContinuous 電壓 | 當使用者選取切線標記/醒目提示做為筆跡工具時,連續觸覺訊號。 | 選擇性 |
EraserContinuous 電壓 | 當使用者選擇橡皮擦作為筆跡工具時連續的觸覺訊號。 | 選擇性 |
GalaxyContinuous 超聲波 (HID 文件和實施指南將此波形稱為 SparkleContinous) |
特殊筆跡工具的連續觸覺訊號,例如多色筆刷。 | 選擇性 |
MarkerContinuous 電壓 | 當使用者選擇標記作為筆跡工具時連續的觸覺訊號。 | 選擇性 |
PencilContinuous 電壓 | 當使用者選擇鉛筆作為筆跡工具時連續的觸覺訊號。 | 選擇性 |
互動波形
互動波形通常很短 (下表中註明的例外情況),根據需要產生直接回授波形,以確認關鍵操作,例如將滑鼠懸停在按鈕上或點擊按鈕、回應操作的完成或吸引使用者的注意。
功能 | 描述 | 必要條件 / 選擇性 |
---|---|---|
點擊波形 | 短暫的「點擊」回饋。 當觸覺筆不支援應用程式選擇的互動波形時,這是預設的後備方案。 | 必要 |
誤差波形 | 強烈訊號提醒使用者操作失敗或發生錯誤。 | 選擇性 |
懸停波形 | 指示使用者已開始將滑鼠懸停在互動式 UI 元素上。 | 選擇性 |
按壓波形 | 指示使用者何時以增量操作按下互動式 UI 元素 (請參閱發布內容)。 | 選擇性 |
釋放波形 | 指示使用者何時以增量操作釋放互動式 UI 元素 (請參閱按下)。 | 選擇性 |
成功波形 | 強烈訊號提醒使用者操作成功。 | 選擇性 |
BuzzContinuous 波形 | 連續嗡嗡作響的感覺。 | 選擇性 |
RumbleContinuous 波形 | 持續的隆隆聲感。 | 選擇性 |
觸覺反饋自訂
某些觸覺筆可以支援以下自訂。
功能 | 描述 | 必要條件 / 選擇性 |
---|---|---|
強度 | 設定觸覺訊號的強度。 | 選擇性 |
播放計數 | 重複觸覺訊號指定次數。 | 選擇性 |
重播暫停間隔 | 設定每次重複播放觸覺訊號之間的時間。 | 選擇性 |
播放持續時間 | 設定觸覺訊號播放的時間間隔。 | 選擇性 |
檢查自訂設定支援
若要檢查強度、播放次數、重播暫停間隔和播放持續時間支持,請使用 SimpleHapticsController 的以下屬性:
發送並停止書寫觸覺反饋
使用 SimpleHapticsController 物件的SendHapticFeedback 方法,將筆跡超聲波傳遞至使用者的手寫筆。 此方法支援傳入一個波形或同時傳入具有自訂強度值的波形 (請參閱自訂觸覺反饋)。
呼叫 SendHapticFeedback 並傳入筆跡波形,以將筆配置為在筆尖接觸螢幕上的任意位置時立即開始播放該波形。 直到畫筆升起或呼叫 StopFeedback,無論第一次發生,都會繼續播放波狀。 我們建議在您想要播放觸覺的元素的 PointerEntered 事件處理程序中執行此操作。 例如,具有自訂筆跡書寫實作的應用程式將在其筆跡書寫畫布的 PointerEntered 方法中執行此操作。
要檢索所需的筆跡波形,您必須迭代 SimpleHapticsController 的 SupportedFeedback 集合,確保它受主動筆支援。
如果不支持,您可以選擇完全不播放任何內容,或回退到 InkContinously 波形,因為保證會支援該波形。
在下面的範例中,我們嘗試傳送 BrushContinously 波形 (但如果不支援 BrushContinously,則回退到 InkContinously)。
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 呼叫。 您仍然需要呼叫 StopFeedback 來取得連續的互動波形。
注意
在播放筆跡書寫波形時發送互動波形將暫時中斷筆跡書寫波形。 當互動波形停止時,筆跡波形將恢復。
要檢索所需的互動波形,您必須迭代 SimpleHapticsController 的 SupportedFeedback 集合,確保它受主動筆支援。
如果不支持,您可以選擇完全不播放任何內容,或回退到 Click 波形,因為保證會支援該波形。
在下面的範例中,我們嘗試傳送 Error 波形 (但如果不支援 Error,則退回到 Click)。
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 支援設定強度,然後使用所需的
Intensity
值呼叫 SendHapticFeedback。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 方法。
- 觸發觸覺回饋:筆跡反饋和互動反饋的反饋。