共用方式為


輸入裝置觸覺實作指南

本文件詳述了連接相容 Windows 11 主機時,觸覺啟用輸入裝置的協定實作。 這不包括對機械約束、電氣限制或元件選擇的指導,以在輸入裝置硬體中產生觸覺響應。

支援的裝置類別

Windows 11 支援以下類型的觸覺啟用輸入裝置:

  • 觸覺觸控板是 Windows 上觸控板裝置類別的延伸模組。 本實作指南會新增至 觸控板實作指南 ,並著重於在觸控板數位轉換器內實作觸覺,因此觸覺觸控板除了包含在這裡的需求之外,還必須符合 觸控板實作指南 中的需求。

  • 觸覺滑鼠是 Windows 上滑鼠裝置類別的擴充。 觸覺小鼠必須符合本文件中所列的要求。

注意:具觸覺功能的筆輸入裝置是本文件中不涵蓋的特殊裝置類別。 關於如何實作帶有觸覺回饋的筆裝置,請參閱 觸覺筆實作指南

輸入裝置觸覺協定實作

需要充分了解 HID 協議才能理解此處提供的信息。 如需 HID 通訊協定的相關資訊,請參閱下列資源:

具觸覺功能的輸入裝置韌體只需報告本主題中描述的使用情況。 Windows 將使用固件和自己的 HID 驅動程序來啟用設備並授予 Windows 應用程序對設備的訪問權限。

每個支援裝置類別的範例描述符已在下方的範例報告描述符章節中提供。

共通指引

本節項目適用於所有類別的輸入觸覺裝置。

必需的 HID 調製

與觸覺相關的功能必須包含在 HID SimpleHapticsController 集合中(頁 0xE,使用0x1)。

對於觸覺觸控板裝置,此集合必須是 Windows 精密觸控板頂層系列的子集。

對於觸覺滑鼠裝置,此集合必須是頂層收藏,且是滑鼠頂層收藏的姊妹收藏。

Device-Initiated 觸覺回饋

具備觸覺功能的輸入裝置可選擇性地支援啟動自身的觸覺回饋,例如對按鈕的按下或放開做出反應。

針對觸覺觸控板,以下「觸覺觸控板指引」章節說明裝置如何選擇支援SET_FEATURE報告,讓使用者在觸發觸覺回饋時自訂行為。

觸覺滑鼠可以觸發裝置發起的回饋,但 Windows 沒有機制來設定這種行為。

Host-Initiated 觸覺回饋

具觸覺功能輸入裝置可支援由主機發起的觸覺回饋,該反饋可在列舉後的任何時間發生。

觸覺觸控板和滑鼠可選擇性支援主機主動回饋。 對於觸覺觸控板,如果支援主機主導的回饋,則必須同時支援兩種SET_FEATURE報告,以便自訂裝置主導的回饋。

支援主機發起的觸覺回饋需要兩個 SimpleHapticsController 邏輯子集合(頁面 0x0E、使用0x01)。 這些邏輯集合必須是裝置類別主 SimpleHapticsController 集合的子集合(如上方「Required HID Collection」章節所述),且必須與用於設定觸控板裝置啟動觸覺回饋強度的集合分開。 其中一個邏輯子集合必須定義主機用來查詢支援波形及其時長的GET_FEATURE報告。 另一個邏輯子集合必須定義一個輸出報告,供主機手動觸發觸覺。

裝置不得宣告支援自動觸發觸覺,且裝置不得支援任何連續波形。

波形

下表定義了主機支援觸覺輸入裝置的波形。 裝置支援的波形與序數相關聯。 波形使用情況和持續時間通過波形信息功能報告提供給主機(見下文)。 觸發反饋時,主機提供所需波形的序數作為手動觸發使用的值。

強制性和選擇性
波形 Description 頁面 ID 強制/選擇性
None 無操作。 不應影響正在進行的波形的播放狀態 0x0E 0x1001 強制的
停止播放正在進行的波形 0x0E 0x1002 強制的
盤旋 用於指示懸停並發出即將採取行動的可能性的光脈衝 0x0E 0x1008 強制的
用於指示與螢幕邊界或滑桿和捲軸末端的衝突的軟脈衝 0x0E 0x1012 強制的
Align 清晰的脈衝,可在與參考線或畫布邊緣進行拖曳、縮放或旋轉互動期間確認物件對齊 0x0E 0x1013 強制的
Step 用於逐步執行滑桿、清單或洗刷器中的項目的堅韌脈衝 0x0E 0x1014 強制的
Grow 傳達運動、轉換或智慧系統活動的動態脈衝 0x0E 0x1015 強制的
裝置判斷表面按鈕已被按下時觸發的觸覺訊號。 如果支援,也必須支援發行。 0x0E 0x1006 可選
釋放 裝置判斷表面按鈕已釋放時觸發的觸覺訊號。 如果支援,也必須支援 Press。 0x0E 0x1007 可選
成功 強烈的觸覺信號提醒用戶操作已成功 0x0E 0x1009 可選
錯誤 強烈觸覺信號提醒用戶操作失敗或發生錯誤 0x0E 0x100A 可選
禁止

不得支援下列波形。

波形 ID 註釋
Click 0x1003 會與按鈕按下的現有觸覺反饋造成混淆。
嗡嗡聲連續 0x1004 不應支援連續波形。
隆隆聲連續 0x1005 不應支援連續波形。
墨水連續 0x100B 僅適用於筆。
鉛筆連續 0x100C 僅適用於筆。
標記連續 0x100D 僅適用於筆。
鑿子標記連續 0x100E 僅適用於筆。
筆刷連續 0x100F 僅適用於筆。
橡皮擦連續 0x1010 僅適用於筆。
閃閃發光連續 0x1011 僅適用於筆。

波形資訊功能報告

主機會在查詢裝置支援的波形時發出此GET_FEATURE報告。 此功能報告必須具有專用的報告 ID。

邏輯集合必須有兩個子邏輯集合,一個用於波形清單,一個用於持續時間清單。 這些集合必須在序數頁面 (0x0A) 上定義使用範圍,以允許主機查詢與每個序數相關聯的波形和持續時間。

強制和選擇性用法
會員 Description 頁面 ID 強制/選擇性
波形清單 邏輯集合,包含裝置支援的觸覺波形排序清單 0x0E 0x10 強制的
持續時間列表 邏輯集合,包含波形清單中波形持續時間的有序清單 0x0E 0x11 強制的
波形清單(必填)

此集合提供序數與對應波形之間的對應。 序數 1 和 2 隱含對應於 WAVEFORM_NONE 和 WAVEFORM_STOP,不需要在描述符中宣告。 因此,集合使用範圍的最小使用量可為 3,且最大使用量應足夠大,以將序數指派給所有支援的波形。

如果使用量上限大於裝置支援的波形數目,裝置應該報告不支援序數的WAVEFORM_NONE。

使用範圍的邏輯範圍應包含所有支援的波形使用方式。 物理範圍和單位必須為 0。

持續時間清單(必填)

此集合提供波形清單中定義的波形持續時間。 集合使用範圍的使用最小值和最大值必須與波形清單的最小值和最大值相同。

離散波形的持續時間必須為零。 WAVEFORM_NONE 和 WAVEFORM_STOP 若指定,必須具有零持續時間。

使用範圍的邏輯最小值必須為零,且邏輯最大值必須至少與最長離散波形的持續時間一樣大。 主機會將邏輯值視為毫秒。 實體範圍必須為零或與邏輯範圍相同。 如果實體範圍和邏輯範圍相符,則單位應該是毫秒。

手動觸發輸出報告

主機會在觸發離散觸覺回饋時發出此報告。 此輸出報告必須具有專用的報告 ID。

強制和選擇性用法
會員 Description 頁面 ID 強制/選擇性
手動觸發 波形作為主機的明確命令觸發 0x0E 0x21 強制的
強烈 反饋的強度 0x0E 0x23 強制的
重複計數 初次播放後重複回饋的次數 0x0E 0x24 可選
重新觸發期間 重複時重新觸發意見反應之前的等待時間 0x0E 0x25 可選
波形截止時間 反饋在被切斷之前可以播放的最大時間 0x0E 0x28 可選
禁止的用途
Usage ID 註釋
自動觸發 0x20 主機不支援。
自動觸發關聯控制項 0x22 主機不支援。
手動觸發(強制)

此使用方式包含波形的序數,如波形資訊功能報告所定義,已要求主機播放。 當包含序WAVEFORM_NONE數以外的序數的輸出報告傳送至裝置時,它應該立即開始播放指定的波形,並包含輸出報告中包含的其他屬性 (強度、重複計數、重新觸發期間、截止時間,如果支援) 。 裝置應該只接受離散波形、WAVEFORM_NONE和WAVEFORM_STOP的序數。 如果序數對應至 WAVEFORM_STOP,則應該停止任何進行中的離散波形播放。 如果序數對應於WAVEFORM_NONE,則不應執行任何動作,且持續的觸覺回饋應該繼續播放。

邏輯範圍必須包含所有可能的序數,包括隱含序數 1 (WAVEFORM_NONE) 和 2 (WAVEFORM_STOP)。 物理範圍和單位必須為 0。

強度(必填)

此用法代表要套用至所要求波形的最大強度百分比,邏輯最大值代表最大強度,邏輯最小值代表完全沒有回饋。

邏輯最小值必須為零,而且應該根據裝置的功能來選取邏輯最大值,例如,如果裝置支援四個強度層級,則邏輯最大值應該為四個。 如果裝置支援更精細的強度,則邏輯最大值可以更大,但不應超過 100。 裝置必須支援至少四個強度層級,因此最小邏輯最大值為四個。 強度為零表示不應播放任何反饋——主機只會將此值用於WAVEFORM_STOP。

物理範圍和單位必須為 0。

重複計數(選用)

此用法表示初始播放後重複波形的次數。 值為零表示波形只能播放一次。

如果支援此使用方式,則也必須支援重新觸發期間和截止時間使用方式。

邏輯最小值必須為零,且邏輯最大值必須大於零。 邏輯最大值應該上限為小值 (例如,10)。 物理範圍和單位必須為 0。

重新觸發期間(選用)

此用法代表波形重新觸發之間的持續時間,從上一個觸發的開始時間開始測量。 零值應解釋為與波形的默認持續時間相同,因此在前一個波形完成後立即重新觸發。 小於波形預設持續時間的值應該會中斷波形並重新啟動它。

如果支援此使用方式,則也必須支援重複計數和截止時間使用方式。

主機會將邏輯值視為毫秒。 邏輯最小值必須為零,且邏輯最大值必須至少為 1000 (代表一秒)。 實體範圍必須為零或與邏輯範圍相同。 如果實體範圍為非零,則單位應該為毫秒。

波形截止時間(可選)

此用法代表單一觸發器可導致播放的最大時間量,並考慮重複計數和重新觸發期間。

如果支援此使用方式,則也必須支援重複計數和重新觸發使用方式。

主機會將邏輯值視為毫秒。 邏輯最小值必須至少與最長離散波形的持續時間一樣大,再乘以重複計數使用的邏輯最大值。 實體範圍必須為零或與邏輯範圍相同。 如果實體範圍為非零,則單位應該為毫秒。

觸覺觸控板導引

本節項目僅適用於觸覺觸控板。

Device-Initiated 觸覺回饋

觸覺觸控板負責在確定觸控板的表面按鈕已被按下或釋放時觸發觸覺回饋。 它可以選擇支援SET_FEATURE報告,以允許使用者在執行此操作時自訂其行為:

  • 觸覺反饋的強度
  • 觸發按下按鈕所需的力

如果觸控板也支援主機起始的觸覺回饋,則這兩個功能報告都是強制性的。 每個報告都必須使用不同的報告 ID,不得與任何其他使用方式搭配使用。

在列舉期間,主機會從描述元評估支持的邏輯和實體範圍,並計算設定UI的公開選項,包括預設值。 主機應發出SET_FEATURE,將使用者指定的值傳達給設備;此發行可能隨時發生,但每當設定變更、使用者切換發生,以及列舉或重設裝置時,都會發生此發行。

觸覺強度特徵報告

此SET_FEATURE報告指定使用者對按下和釋放按鈕的觸覺回饋強度的偏好。 如果裝置支援,它不適用於任何主機起始的意見反應強度。 若要支援此設定,裝置必須在 Windows 精準式觸控板最上層集合中定義 SimpleHapticsController 邏輯子集合 (第 0x0E 頁、使用方式 0x01) ,其中包含觸覺強度使用方式 (第 0x0E 頁、使用方式 0x23) 作為具有專用報表識別碼的功能報表。 此子集合不得包含自動觸發程式 (第 0x0E 頁、使用情形0x20) 或手動觸發程式 (第 0x0E 頁、使用情形0x21) 使用方式。

邏輯最小值必須等於零。 使用者的偏好設定將線性縮放到邏輯範圍內,零表示不應觸發按鈕按下和釋放的回饋。

按鈕按下臨界值功能報告

此SET_FEATURE報告指定使用者對觸發按鈕按下所需力的偏好設定。 若要支援此設定,裝置必須將按鈕按下閾值使用方式 (第 0x0D 頁、使用量 0xB0) 定義為功能報告,並在 Windows 精準式觸控板最上層集合中具有專用報告識別碼。

邏輯範圍應以線性方式對應至值的實體範圍,並以預設值為中心進行平均間距和置中。 取得邏輯範圍時,預設會使用下列公式來計算:

顯示計算邏輯單元中預設按鈕按下臨界值之公式的圖表

[邏輯最小值]、[預設] 和 [邏輯最大值] 會分別對應到透過 Windows 設定 UI 向使用者公開的 3 個不同的按鈕按下層級(分別支援 「低」、「中」和「高」)。

按鈕按下閾值的建議實體範圍至少涵蓋介於 110g 到 190g 之間的範圍,分別對應到最小值和最大值。 如需使用實體最大值 190g 的範例描述元,以及實體最小值為 110g(因此,根據上述公式,預設值為 150g)請參閱 範例報告描述元

HID 報告描述範例

觸覺觸控板描述符範例

下列描述元支援所有必要和選擇性用法。 它宣稱支援五種波形,最長的波形持續時間為 50 毫秒。

所有邏輯範圍都應根據裝置支援進行更新。 若要支援不同數量的波形:

  • 必須更新「手動觸發」使用量的邏輯範圍
  • 必須更新波形清單和持續時間清單的使用範圍和報告計數

若要支援不同的最形長度,必須更新下列邏輯範圍:

  • 重新觸發週期(輸出)
  • 波形截止時間(輸出)
  • 持續時間清單 (功能)
0x05, 0x0D,       // UsagePage(Digitizers[0x000D])
0x09, 0x05,       // UsageId(Touch Pad[0x0005])
0xA1, 0x01,       // Collection(Application)
0x85, 0x40,       //  ReportId(64)
0x05, 0x0D,       //  UsagePage(Digitizers[0x000D])
0x09, 0xB0,       //  UsageId(Button Press Threshold[0x00B0])
0x35, 0x6E,       //  PhysicalMinimum(110)
0x46, 0xBE, 0x00, //  PhysicalMaximum(190)
0x66, 0x01, 0x01, //  Unit('gram', SiLinear, Gram:1)
0x55, 0x00,       //  UnitExponent(1)
0x15, 0x01,       //  LogicalMinimum(1)
0x25, 0x03,       //  LogicalMaximum(3)
0x95, 0x01,       //  ReportCount(1)
0x75, 0x08,       //  ReportSize(8)
0xB1, 0x02,       //  Feature(Data, Variable, Absolute)
0x85, 0x41,       //  ReportId(65)
0x05, 0x0E,       //  UsagePage(Haptics[0x000E])
0x09, 0x01,       //  UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x02,       //  Collection(Logical)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x23,       //   UsageId(Intensity[0x0023])
0x35, 0x00,       //   PhysicalMinimum(0)
0x45, 0x00,       //   PhysicalMaximum(0)
0x65, 0x00,       //   Unit(None)
0x55, 0x00,       //   UnitExponent(1)
0x15, 0x00,       //   LogicalMinimum(0)
0x25, 0x04,       //   LogicalMaximum(4)
0x95, 0x01,       //   ReportCount(1)
0x75, 0x08,       //   ReportSize(8)
0xB1, 0x02,       //   Feature(Data, Variable, Absolute)
0xC0,             //  EndCollection()
0x85, 0x42,       //  ReportId(66)
0x05, 0x0E,       //  UsagePage(Haptics[0x000E])
0x09, 0x01,       //  UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x02,       //  Collection(Logical)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x10,       //   UsageId(Waveform List[0x0010])
0xA1, 0x02,       //   Collection(Logical)
0x05, 0x0A,       //    UsagePage(Ordinal[0x000A])
0x19, 0x03,       //    UsageIdMin(Instance 3[0x0003])
0x29, 0x07,       //    UsageIdMax(Instance 7[0x0007])
0x35, 0x00,       //    PhysicalMinimum(0)
0x45, 0x00,       //    PhysicalMaximum(0)
0x65, 0x00,       //    Unit(None)
0x55, 0x00,       //    UnitExponent(1)
0x16, 0x03, 0x10, //    LogicalMinimum(4,099)
0x26, 0xFF, 0x2F, //    LogicalMaximum(12,287)
0x95, 0x05,       //    ReportCount(5)
0x75, 0x10,       //    ReportSize(16)
0xB1, 0x02,       //    Feature(Data, Variable, Absolute)
0xC0,             //   EndCollection()
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x11,       //   UsageId(Duration List[0x0011])
0xA1, 0x02,       //   Collection(Logical)
0x05, 0x0A,       //    UsagePage(Ordinal[0x000A])
0x19, 0x03,       //    UsageIdMin(Instance 3[0x0003])
0x29, 0x07,       //    UsageIdMax(Instance 7[0x0007])
0x35, 0x00,       //    PhysicalMinimum(0)
0x45, 0x32,       //    PhysicalMaximum(50)
0x66, 0x01, 0x10, //    Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D,       //    UnitExponent(0.001)
0x15, 0x00,       //    LogicalMinimum(0)
0x25, 0x32,       //    LogicalMaximum(50)
0x95, 0x05,       //    ReportCount(5)
0x75, 0x08,       //    ReportSize(8)
0xB1, 0x02,       //    Feature(Data, Variable, Absolute)
0xC0,             //   EndCollection()
0xC0,             //  EndCollection()
0x85, 0x43,       //  ReportId(67)
0x05, 0x0E,       //  UsagePage(Haptics[0x000E])
0x09, 0x01,       //  UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x02,       //  Collection(Logical)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x21,       //   UsageId(Manual Trigger[0x0021])
0x35, 0x00,       //   PhysicalMinimum(0)
0x45, 0x00,       //   PhysicalMaximum(0)
0x65, 0x00,       //   Unit(None)
0x55, 0x00,       //   UnitExponent(1)
0x15, 0x01,       //   LogicalMinimum(1)
0x25, 0x07,       //   LogicalMaximum(7)
0x95, 0x01,       //   ReportCount(1)
0x75, 0x08,       //   ReportSize(8)
0x91, 0x02,       //   Output(Data, Variable, Absolute)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x23,       //   UsageId(Intensity[0x0023])
0x35, 0x00,       //   PhysicalMinimum(0)
0x45, 0x00,       //   PhysicalMaximum(0)
0x65, 0x00,       //   Unit(None)
0x55, 0x00,       //   UnitExponent(1)
0x15, 0x00,       //   LogicalMinimum(0)
0x25, 0x04,       //   LogicalMaximum(4)
0x95, 0x01,       //   ReportCount(1)
0x75, 0x08,       //   ReportSize(8)
0x91, 0x02,       //   Output(Data, Variable, Absolute)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x24,       //   UsageId(Repeat Count[0x0024])
0x35, 0x00,       //   PhysicalMinimum(0)
0x45, 0x00,       //   PhysicalMaximum(0)
0x65, 0x00,       //   Unit(None)
0x55, 0x00,       //   UnitExponent(1)
0x15, 0x00,       //   LogicalMinimum(0)
0x25, 0x05,       //   LogicalMaximum(5)
0x95, 0x01,       //   ReportCount(1)
0x75, 0x08,       //   ReportSize(8)
0x91, 0x02,       //   Output(Data, Variable, Absolute)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x25,       //   UsageId(Retrigger Period[0x0025])
0x35, 0x00,       //   PhysicalMinimum(0)
0x46, 0xE8, 0x03, //   PhysicalMaximum(1,000)
0x66, 0x01, 0x10, //   Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D,       //   UnitExponent(0.001)
0x15, 0x00,       //   LogicalMinimum(0)
0x26, 0xE8, 0x03, //   LogicalMaximum(1,000)
0x95, 0x01,       //   ReportCount(1)
0x75, 0x10,       //   ReportSize(16)
0x91, 0x02,       //   Output(Data, Variable, Absolute)
0x05, 0x0E,       //   UsagePage(Haptics[0x000E])
0x09, 0x28,       //   UsageId(Waveform Cutoff Time[0x0028])
0x36, 0xE8, 0x03, //   PhysicalMinimum(1,000)
0x46, 0x88, 0x13, //   PhysicalMaximum(5,000)
0x66, 0x01, 0x10, //   Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D,       //   UnitExponent(0.001)
0x16, 0xE8, 0x03, //   LogicalMinimum(1,000)
0x26, 0x88, 0x13, //   LogicalMaximum(5,000)
0x95, 0x01,       //   ReportCount(1)
0x75, 0x10,       //   ReportSize(16)
0x91, 0x02,       //   Output(Data, Variable, Absolute)
0xC0,             //  EndCollection()
0xC0,             // EndCollection()

上述描述符是透過下列 Waratah 檔案產生的:

[[settings]]
packingInBytes = 1
optimize = false

[[unit]]
name = 'millisecond'
second = [0.001, 1.0]

[[applicationCollection]]
usage = ['Digitizers', 'Touch Pad']

 # Button press threshold feature report
 [[applicationCollection.featureReport]]
 id = 0x40

  [[applicationCollection.featureReport.variableItem]]
  usage = ['Digitizers', 'Button Press Threshold']
  logicalValueRange = [1, 3]
  physicalValueRange = [110, 190]
  unit = 'gram'

 # Feedback intensity feature report
 [[applicationCollection.featureReport]]
 id = 0x41

  [[applicationCollection.featureReport.logicalCollection]]
  usage = ['Haptics', 'Simple Haptic Controller']

   [[applicationCollection.featureReport.logicalCollection.variableItem]]
   usage = ['Haptics', 'Intensity']
   logicalValueRange = [0, 4]

 # Host-initiated waveform information feature report
 [[applicationCollection.featureReport]]
 id = 0x42

  [[applicationCollection.featureReport.logicalCollection]]
  usage = ['Haptics', 'Simple Haptic Controller']

   [[applicationCollection.featureReport.logicalCollection.logicalCollection]]
   usage = ['Haptics', 'Waveform List']

    [[applicationCollection.featureReport.logicalCollection.logicalCollection.variableItem]]
    usageRange = ['Ordinal', 'Instance 3', 'Instance 7']
    logicalValueRange = [0x1003, 0x2FFF]

   [[applicationCollection.featureReport.logicalCollection.logicalCollection]]
   usage = ['Haptics', 'Duration List']

    [[applicationCollection.featureReport.logicalCollection.logicalCollection.variableItem]]
    usageRange = ['Ordinal', 'Instance 3', 'Instance 7']
    logicalValueRange = [0, 50]
    physicalValueRange = [0, 50]
    unit = 'millisecond'

 # Host-initiated waveform manual trigger output report
 [[applicationCollection.outputReport]]
 id = 0x43

  [[applicationCollection.outputReport.logicalCollection]]
  usage = ['Haptics', 'Simple Haptic Controller']

   [[applicationCollection.outputReport.logicalCollection.variableItem]]
   usage = ['Haptics', 'Manual Trigger']
   logicalValueRange = [1, 7]

   [[applicationCollection.outputReport.logicalCollection.variableItem]]
   usage = ['Haptics', 'Intensity']
   logicalValueRange = [0, 4]

   [[applicationCollection.outputReport.logicalCollection.variableItem]]
   usage = ['Haptics', 'Repeat Count']
   logicalValueRange = [0, 5]

   [[applicationCollection.outputReport.logicalCollection.variableItem]]
   usage = ['Haptics', 'Retrigger Period']
   logicalValueRange = [0, 1000]
   physicalValueRange = [0, 1000]
   unit = 'millisecond'

   [[applicationCollection.outputReport.logicalCollection.variableItem]]
   usage = ['Haptics', 'Waveform Cutoff Time']
   logicalValueRange = [1000, 5000]
   physicalValueRange = [1000, 5000]
   unit = 'millisecond'

觸覺鼠描述符範例

下列描述元支援所有必要和選擇性用法。 它宣稱支援八種波形,最長的波形持續時間為 200 毫秒。

所有邏輯範圍都應根據裝置支援進行更新。 若要支援不同數量的波形:

  • 必須更新「手動觸發」使用量的邏輯範圍
  • 必須更新波形清單和持續時間清單的使用範圍和報告計數

若要支援不同的最形長度,必須更新下列邏輯範圍:

  • 重新觸發週期(輸出)
  • 波形截止時間(輸出)
  • 持續時間清單 (功能)
0x05, 0x01,       // UsagePage(Generic Desktop[0x0001])
0x09, 0x02,       // UsageId(Mouse[0x0002])
0xA1, 0x01,       // Collection(Application)
0x85, 0x01,       //  ReportId(1)
0x09, 0x01,       //  UsageId(Pointer[0x0001])
0xA1, 0x00,       //  Collection(Physical)
0x09, 0x30,       //   UsageId(X[0x0030])
0x09, 0x31,       //   UsageId(Y[0x0031])
0x15, 0x80,       //   LogicalMinimum(-128)
0x25, 0x7F,       //   LogicalMaximum(127)
0x95, 0x02,       //   ReportCount(2)
0x75, 0x08,       //   ReportSize(8)
0x81, 0x06,       //   Input(Data, Variable, Relative)
0x05, 0x09,       //   UsagePage(Button[0x0009])
0x19, 0x01,       //   UsageIdMin(Button 1[0x0001])
0x29, 0x03,       //   UsageIdMax(Button 3[0x0003])
0x15, 0x00,       //   LogicalMinimum(0)
0x25, 0x01,       //   LogicalMaximum(1)
0x95, 0x03,       //   ReportCount(3)
0x75, 0x01,       //   ReportSize(1)
0x81, 0x02,       //   Input(Data, Variable, Absolute)
0xC0,             //  EndCollection()
0x95, 0x01,       //  ReportCount(1)
0x75, 0x05,       //  ReportSize(5)
0x81, 0x03,       //  Input(Constant, Variable, Absolute)
0xC0,             // EndCollection()
0x05, 0x0E,       // UsagePage(Haptics[0x000E])
0x09, 0x01,       // UsageId(Simple Haptic Controller[0x0001])
0xA1, 0x01,       // Collection(Application)
0x85, 0x10,       //  ReportId(16)
0x09, 0x10,       //  UsageId(Waveform List[0x0010])
0xA1, 0x02,       //  Collection(Logical)
0x05, 0x0A,       //   UsagePage(Ordinal[0x000A])
0x19, 0x03,       //   UsageIdMin(Instance 3[0x0003])
0x29, 0x0A,       //   UsageIdMax(Instance 10[0x000A])
0x16, 0x03, 0x10, //   LogicalMinimum(4,099)
0x26, 0xFF, 0x2F, //   LogicalMaximum(12,287)
0x95, 0x08,       //   ReportCount(8)
0x75, 0x0E,       //   ReportSize(14)
0xB1, 0x02,       //   Feature(Data, Variable, Absolute)
0xC0,             //  EndCollection()
0x05, 0x0E,       //  UsagePage(Haptics[0x000E])
0x09, 0x11,       //  UsageId(Duration List[0x0011])
0xA1, 0x02,       //  Collection(Logical)
0x05, 0x0A,       //   UsagePage(Ordinal[0x000A])
0x19, 0x03,       //   UsageIdMin(Instance 3[0x0003])
0x29, 0x0A,       //   UsageIdMax(Instance 10[0x000A])
0x46, 0xC8, 0x00, //   PhysicalMaximum(200)
0x66, 0x01, 0x10, //   Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D,       //   UnitExponent(0.001)
0x15, 0x00,       //   LogicalMinimum(0)
0x26, 0xC8, 0x00, //   LogicalMaximum(200)
0x75, 0x08,       //   ReportSize(8)
0xB1, 0x02,       //   Feature(Data, Variable, Absolute)
0xC0,             //  EndCollection()
0x85, 0x11,       //  ReportId(17)
0x05, 0x0E,       //  UsagePage(Haptics[0x000E])
0x09, 0x21,       //  UsageId(Manual Trigger[0x0021])
0x45, 0x00,       //  PhysicalMaximum(0)
0x65, 0x00,       //  Unit(None)
0x55, 0x00,       //  UnitExponent(1)
0x15, 0x01,       //  LogicalMinimum(1)
0x25, 0x0A,       //  LogicalMaximum(10)
0x95, 0x01,       //  ReportCount(1)
0x75, 0x04,       //  ReportSize(4)
0x91, 0x02,       //  Output(Data, Variable, Absolute)
0x09, 0x23,       //  UsageId(Intensity[0x0023])
0x15, 0x00,       //  LogicalMinimum(0)
0x25, 0x04,       //  LogicalMaximum(4)
0x75, 0x03,       //  ReportSize(3)
0x91, 0x02,       //  Output(Data, Variable, Absolute)
0x09, 0x24,       //  UsageId(Repeat Count[0x0024])
0x25, 0x05,       //  LogicalMaximum(5)
0x91, 0x02,       //  Output(Data, Variable, Absolute)
0x09, 0x25,       //  UsageId(Retrigger Period[0x0025])
0x46, 0xE8, 0x03, //  PhysicalMaximum(1,000)
0x66, 0x01, 0x10, //  Unit('millisecond', SiLinear, Seconds:1)
0x55, 0x0D,       //  UnitExponent(0.001)
0x26, 0xE8, 0x03, //  LogicalMaximum(1,000)
0x75, 0x0A,       //  ReportSize(10)
0x91, 0x02,       //  Output(Data, Variable, Absolute)
0x09, 0x28,       //  UsageId(Waveform Cutoff Time[0x0028])
0x36, 0xE8, 0x03, //  PhysicalMinimum(1,000)
0x46, 0x88, 0x13, //  PhysicalMaximum(5,000)
0x16, 0xE8, 0x03, //  LogicalMinimum(1,000)
0x26, 0x88, 0x13, //  LogicalMaximum(5,000)
0x75, 0x0D,       //  ReportSize(13)
0x91, 0x02,       //  Output(Data, Variable, Absolute)
0x75, 0x07,       //  ReportSize(7)
0x91, 0x03,       //  Output(Constant, Variable, Absolute)
0xC0,             // EndCollection()

上述描述符是透過下列 Waratah 檔案產生的:

[[unit]]
name = 'millisecond'
second = [0.001, 1.0]

[[applicationCollection]]
usage = ['Generic Desktop', 'Mouse']

 # Mouse
 [[applicationCollection.inputReport]]

  [[applicationCollection.inputReport.physicalCollection]]
  usage = ['Generic Desktop', 'Pointer']

   [[applicationCollection.inputReport.physicalCollection.variableItem]]
   usage = ['Generic Desktop', 'X']
   sizeInBits = 8
   logicalValueRange = 'maxSignedSizeRange'
   reportFlags = ['relative']

   [[applicationCollection.inputReport.physicalCollection.variableItem]]
   usage = ['Generic Desktop', 'Y']
   sizeInBits = 8
   logicalValueRange = 'maxSignedSizeRange'
   reportFlags = ['relative']

   [[applicationCollection.inputReport.physicalCollection.variableItem]]
   usageRange = ['Button', 'Button 1', 'Button 3']
   logicalValueRange = [0, 1]

[[applicationCollection]]
usage = ['Haptics', 'Simple Haptic Controller']

 # Host-initiated waveform information feature report
 [[applicationCollection.featureReport]]
 id = 0x10

  [[applicationCollection.featureReport.logicalCollection]]
  usage = ['Haptics', 'Waveform List']

   [[applicationCollection.featureReport.logicalCollection.variableItem]]
   usageRange = ['Ordinal', 'Instance 3', 'Instance 10']
   logicalValueRange = [0x1003, 0x2FFF]

  [[applicationCollection.featureReport.logicalCollection]]
  usage = ['Haptics', 'Duration List']

   [[applicationCollection.featureReport.logicalCollection.variableItem]]
   usageRange = ['Ordinal', 'Instance 3', 'Instance 10']
   logicalValueRange = [0, 200]
   physicalValueRange = [0, 200]
   unit = 'millisecond'

 # Host-initiated waveform manual trigger output report
 [[applicationCollection.outputReport]]
 id = 0x11

  [[applicationCollection.outputReport.variableItem]]
  usage = ['Haptics', 'Manual Trigger']
  logicalValueRange = [1, 10]

  [[applicationCollection.outputReport.variableItem]]
  usage = ['Haptics', 'Intensity']
  logicalValueRange = [0, 4]

  [[applicationCollection.outputReport.variableItem]]
  usage = ['Haptics', 'Repeat Count']
  logicalValueRange = [0, 5]

  [[applicationCollection.outputReport.variableItem]]
  usage = ['Haptics', 'Retrigger Period']
  logicalValueRange = [0, 1000]
  physicalValueRange = [0, 1000]
  unit = 'millisecond'

  [[applicationCollection.outputReport.variableItem]]
  usage = ['Haptics', 'Waveform Cutoff Time']
  logicalValueRange = [1000, 5000]
  physicalValueRange = [1000, 5000]
  unit = 'millisecond'