共用方式為


手寫筆互動和觸覺 (觸碰) 回饋

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 方法中完成這件事。

要取得所需的描線波形,必須遍歷 SimpleHapticsControllerSupportedFeedback 集合,確保該波形由主動筆支援。

如果不支援,你可以選擇完全不播放任何內容,或者回退到 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 來取得連續的互動波形。

備註

在播放描線波形時發送互動波形會暫時中斷該波形。 當互動波形停止時,墨線波形會恢復。

要取得所需的互動波形,你必須遍歷 SimpleHapticsControllerSupportedFeedback 集合,確保該集合由主動筆支援。

如果不支援,你可以選擇完全不播放任何東西,或是退回 點擊波形 ,因為那是保證支援的。

在以下範例中,我們嘗試傳送 錯誤 波形(但若不支援 錯誤,則回退至 點擊 波形)。

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

自訂觸覺回饋

有三種方式可以自訂觸覺回饋。 第一類有墨線和互動回饋支持,第二和第三種則僅靠互動回饋支持。

  1. 調整反饋強度相對於系統最大強度設定。 為此,你必須先檢查 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);
            }
        }
    }
    
  2. 重複指定次數的觸覺訊號。 為此,你必須先確認 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);
            }
        }
    }
    
  3. 設定觸覺訊號的持續時間。 為此,你必須先確認 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);
            }
        }
    }
    

範例

以下功能的操作範例請參考 筆觸覺範例