本文件詳述了連接相容 Windows 11 主機時,觸覺支援輸入裝置的協定實作。 這不包括對機械約束、電氣限制或元件選擇的指導,以在輸入裝置硬體中產生觸覺響應。
支援的裝置類別
Windows 11 支援以下類型的觸覺啟用輸入裝置:
觸覺觸控板是 Windows 上觸控板裝置類別的擴充。 本實作指南會新增至 觸控板實作指南 ,並著重於在觸控板數位轉換器內實作觸覺,因此觸覺觸控板除了包含在這裡的需求之外,還必須符合 觸控板實作指南 中的需求。
觸覺滑鼠是 Windows 上滑鼠裝置類別的擴充。 觸覺小鼠必須符合本文件中所列的要求。
備註
觸覺觸控筆輸入裝置是本文件中不涵蓋的特殊裝置類別。 關於如何實作帶有觸覺回饋的筆裝置,請參閱 觸覺筆實作指南。
輸入裝置觸覺協定實作
需要充分了解 HID 協議才能理解此處提供的信息。 如需 HID 通訊協定的相關資訊,請參閱下列資源:
具觸覺功能的輸入裝置韌體只需報告本主題中描述的使用情況。 Windows 會使用韌體和自家的 HID 驅動程式來啟用裝置,讓 Windows 應用程式存取裝置。
每個支援裝置類別的範例描述符已在下方的範例報告描述符章節中提供。
主機發起的觸覺回饋
具觸覺功能的輸入裝置可支援由主機發起的觸覺反饋,該反饋可在枚舉後隨時觸發。 與觸覺相關的功能必須包含在 HID SimpleHapticsController 集合中(頁碼 0x0E,使用 0x01)。
- 對於觸控板,這個集合必須是 Windows Precision Touchpad 頂層系列的子集。
- 對於滑鼠,此集合必須是頂層集合,且為滑鼠頂層集合的同層級集合。
支援主機發起的觸覺回饋需要 HID 報告:
- GET_FEATURE報告,供主機用來查詢支援波形及其持續時間。 請參閱下方「波形資訊特徵報告」章節。
- 主機用來手動觸發觸覺的 OUTPUT 報告。 請參閱下方「手動觸發輸出報告」章節。
對於觸控板,這些報告必須定義在兩個 SimpleHapticsController 的邏輯子集合中,而這些邏輯子集合則隸屬於主 SimpleHapticsController 子集合。 對於滑鼠,這些報告可以直接在頂層集合中定義。
波形
下表定義了主機支援觸覺輸入裝置的波形。 裝置支援的波形與序數相關聯。 波形使用情況和持續時間通過波形信息功能報告提供給主機(見下文)。 觸發反饋時,主機提供所需波形的序數作為手動觸發使用的值。
強制性和選擇性
| 波形 | Description | 頁面 | ID | 強制/選擇性 |
|---|---|---|---|---|
| None | 無操作。 不應影響正在播放的波形狀態。 | 0x0E | 0x1001 | 強制的 |
| 停 | 停止播放正在進行的波形 | 0x0E | 0x1002 | 強制的 |
| 盤旋 | 光脈衝顯示懸停狀態,提示潛在的即將進行的操作。 | 0x0E | 0x1008 | 強制的 |
| 撞 | 軟脈衝表示達到邊界或極限 | 0x0E | 0x1012 | 強制的 |
| Align | 當物體卡在對準導軌上時,會發出銳利的脈衝 | 0x0E | 0x1013 | 強制的 |
| Step | 對於離散變化(例如步驟或數值的移動)提供穩定的脈衝 | 0x0E | 0x1014 | 強制的 |
| 成長 | 傳達運動、轉換或智慧系統活動的動態脈衝 | 0x0E | 0x1015 | 強制的 |
| 壓 | 代表按下按鈕的脈衝 | 0x0E | 0x1006 | 請參閱下方 |
| 釋放 | 代表按鈕釋放的脈衝 | 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 隱含地對應於None和Stop,且不必在描述符中宣告。 因此,集合使用範圍的最小值可以是 3,而最大值必須足夠大,以分配序數給所有支援的波形。 序數 3 以上沒有必須的波形指派順序——只有序數 1 和 2 有固定定義。
如果使用量最大值大於裝置支援的波形數,裝置應對未支援的序數回報為「無」。
使用範圍的邏輯範圍必須包含所有支援的波形使用方式。 物理範圍和單位必須為 0。
持續時間清單(必填)
此集合提供波形清單中定義的波形持續時間。 集合使用範圍的使用最小值和最大值必須與波形清單的最小值和最大值相同。
離散波形的持續時間必須大於零。 若指定為 None 與 Stop,則其持續時間必須為零。
使用範圍的邏輯最小值必須為零,且邏輯最大值必須至少與最長離散波形的持續時間一樣大。 主機會將邏輯值視為毫秒。 實體範圍必須為零或與邏輯範圍相同。 若物理距離與邏輯距離相符,單位必須為毫秒。
手動觸發輸出報告
主機會在觸發離散觸覺回饋時發出此報告。 此輸出報告必須具有專用的報告 ID。
強制和選擇性用法
| 會員 | Description | 頁面 | ID | 強制/選擇性 |
|---|---|---|---|---|
| 手動觸發 | 波形作為主機的明確命令觸發 | 0x0E | 0x21 | 強制的 |
| 強度 | 反饋的強度 | 0x0E | 0x23 | 強制的 |
| 重複計數 | 初次播放後重複回饋的次數 | 0x0E | 0x24 | 請參閱下方 |
| 重新觸發期間 | 重複時重新觸發意見反應之前的等待時間 | 0x0E | 0x25 | 請參閱下方 |
| 波形截止時間 | 在反饋被切斷之前,可以播放的最大時間 | 0x0E | 0x28 | 請參閱下方 |
重複計數、 重觸發週期和 波形截止時間 為可選,但若支援其中一項,另外兩項也必須支援。
禁止的用途
| Usage | ID | 註釋 |
|---|---|---|
| 自動觸發 | 0x20 | 主機不支援。 |
| 自動觸發關聯控制項 | 0x22 | 主機不支援。 |
手動觸發(強制)
此使用方式包含波形的序數,如波形資訊功能報告所定義,已要求主機播放。 當輸出報告中包含非 None 的序數被傳送到裝置時,裝置應立即開始播放指定的波形,同時包括輸出報告中的額外屬性(如強度、重複次數、重觸發週期、截止時間等,若裝置支援這些屬性)。 裝置應僅在離散波形、無和停止時僅接受序數。 若序數對應 停止,應停止任何正在進行的離散波形播放。 若序數對應 為 None,則不應執行任何動作,持續播放觸覺反饋。
邏輯範圍必須包含所有可能的序數,包括隱含的序數 1(無)與 2(停止)。 物理範圍和單位必須為 0。
強度(必填)
此用法代表要套用至所要求波形的最大強度百分比,邏輯最大值代表最大強度,邏輯最小值代表完全沒有回饋。
邏輯最小值必須為零,邏輯最大值應根據裝置能力選擇——例如,若裝置支援四級強度,邏輯最大值應為四級。 若裝置支援更細緻的強度,邏輯最大值可更大,但不得超過 100。 裝置必須支援至少四個強度層級,因此最小邏輯最大值為四個。 強度為零表示不應播放反饋——主持人只會用此數值來表示 停止。
物理範圍和單位必須為 0。
重複計數(選用)
此用法表示初始播放後重複波形的次數。 值為零表示波形只能播放一次。
如果支援此使用方式,則也必須支援重新觸發時間段和截止時間點使用方式。
邏輯最小值必須為零,且邏輯最大值必須大於零。 邏輯最大值應該被限制在合理的值(例如10)。 物理範圍和單位必須為 0。
重新觸發時間(選用)
此用法代表波形重新觸發之間的持續時間,從上一個觸發的開始時間開始測量。 零值應解釋為與波形的默認持續時間相同,因此在前一個波形完成後立即重新觸發。 小於波形預設持續時間的值應該會中斷波形並重新啟動它。
如果支援此使用方式,則也必須支援重複計數和截止時間使用方式。
主機會將邏輯值視為毫秒。 邏輯最小值必須為零,且邏輯最大值必須至少為 1000 (代表一秒)。 實體範圍必須為零或與邏輯範圍相同。 若物理距離非零,單位必須為毫秒。
波形截止時間(可選)
此用法代表單一觸發器可導致播放的最大時間量,並考慮重複計數和重新觸發期間。
若支援此使用,則重覆計數與重觸發時間使用也必須支援。
主機會將邏輯值視為毫秒。 邏輯最小值必須至少等於最長離散波形的持續時間,再乘以重複計數使用量的邏輯最大值加一。 此邏輯最小值代表觸發最長波形且支援最多重複觸發次數且重觸發間無延遲的持續時間。 為防止單一請求產生過長的觸覺回饋時間,可由裝置自行決定限制邏輯最大值。 實體範圍必須為零或與邏輯範圍相同。 若物理距離非零,單位必須為毫秒。
觸覺觸控板導引
本節項目僅適用於觸覺觸控板。
裝置啟動的觸覺回饋
觸覺觸控板負責在確定觸控板的表面按鈕已被按下或釋放時觸發觸覺回饋。 它可以選擇支援SET_FEATURE報告,以允許使用者在執行此操作時自訂其行為:
- 觸覺反饋的強度
- 觸發按下按鈕所需的力
如果觸控板也支援主機起始的觸覺回饋,則這兩個功能報告都是強制性的。 每個報告都必須使用不同的報告 ID,不得與任何其他使用方式搭配使用。
在列舉期間,主機會從描述符中評估支援的邏輯範圍和物理範圍,並計算設定介面的公開選項,包括預設值。 主機應發出該SET_FEATURE,將使用者指定的數值傳達給裝置;此發布可於任何時間發生,但必須在設定變更、使用者切換,以及裝置列舉或重置時發生。 在SET_FEATURE報告發布前,裝置應使用其合理選擇的預設值(例如邏輯範圍的中間值)。
觸覺強度特徵報告
此SET_FEATURE報告指定使用者對按下和釋放按鈕的觸覺回饋強度的偏好。 如果裝置支援,則不適用於任何由主機發起的意見反應強度。 為支援此配置,裝置必須在 Windows Precision Touchpad 頂層集合中定義一個 SimpleHapticsController 邏輯子集合(頁面 0x0E,使用0x01),其中包含觸覺強度使用量(頁面 0x0E,使用0x23)作為功能報告並有專用報告 ID。 此子集合不得包含自動觸發程式 (第 0x0E 頁、使用情形0x20) 或手動觸發程式 (第 0x0E 頁、使用情形0x21) 使用方式。 它必須與用於主機發起觸覺回饋的 SimpleHapticsController 子集合(若支援)分開。
邏輯最小值必須等於零,邏輯最大值必須大於或等於四。 使用者的偏好設定將被線性縮放至邏輯範圍內,當為零時,表示不應觸發與按鈕按下及釋放相關的回饋。
按鈕按下臨界值功能報告
此SET_FEATURE報告指定使用者對觸發按鈕按下所需力的偏好設定。 為支援此配置,裝置必須在 Windows Precision 觸控板頂層集合中,將「按鈕壓力門檻用途」(頁面 0x0D,用途 0xB0)定義為具有專用報告 ID 的功能報告。 它不能存在於 SimpleHapticsController 的邏輯集合中。
邏輯範圍應以線性方式對應至物理範圍,並以預設值為中心均勻分佈。 取得邏輯範圍時,預設會使用下列公式來計算:
邏輯最小值、預設值與邏輯最大值,分別對應 Windows 設定介面中對使用者呈現的三種不同按鍵力度等級(分別支援「低」、「中」與「高」)。
按鈕按下閾值的建議實體範圍至少涵蓋介於 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, 0x01, 0x10, // LogicalMinimum(4,097)
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 = [0x1001, 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, 0x01, 0x10, // LogicalMinimum(4,097)
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 = [0x1001, 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'