@openmouse/protocol 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (547) hide show
  1. package/CONTRIBUTING.md +167 -0
  2. package/README.md +89 -0
  3. package/dist/asus/index.d.ts +52 -0
  4. package/dist/asus/index.d.ts.map +1 -0
  5. package/dist/asus/index.js +248 -0
  6. package/dist/asus/index.js.map +1 -0
  7. package/dist/atk/index.d.ts +200 -0
  8. package/dist/atk/index.d.ts.map +1 -0
  9. package/dist/atk/index.js +480 -0
  10. package/dist/atk/index.js.map +1 -0
  11. package/dist/bitmouse/index.d.ts +284 -0
  12. package/dist/bitmouse/index.d.ts.map +1 -0
  13. package/dist/bitmouse/index.js +396 -0
  14. package/dist/bitmouse/index.js.map +1 -0
  15. package/dist/compx/codec.d.ts +31 -0
  16. package/dist/compx/codec.d.ts.map +1 -0
  17. package/dist/compx/codec.js +50 -0
  18. package/dist/compx/codec.js.map +1 -0
  19. package/dist/corsair/index.d.ts +147 -0
  20. package/dist/corsair/index.d.ts.map +1 -0
  21. package/dist/corsair/index.js +223 -0
  22. package/dist/corsair/index.js.map +1 -0
  23. package/dist/dareu/index.d.ts +136 -0
  24. package/dist/dareu/index.d.ts.map +1 -0
  25. package/dist/dareu/index.js +344 -0
  26. package/dist/dareu/index.js.map +1 -0
  27. package/dist/drivers/asus/hid.d.ts +29 -0
  28. package/dist/drivers/asus/hid.d.ts.map +1 -0
  29. package/dist/drivers/asus/hid.js +419 -0
  30. package/dist/drivers/asus/hid.js.map +1 -0
  31. package/dist/drivers/atk/bitmouse-hid.d.ts +80 -0
  32. package/dist/drivers/atk/bitmouse-hid.d.ts.map +1 -0
  33. package/dist/drivers/atk/bitmouse-hid.js +501 -0
  34. package/dist/drivers/atk/bitmouse-hid.js.map +1 -0
  35. package/dist/drivers/atk/hid.d.ts +163 -0
  36. package/dist/drivers/atk/hid.d.ts.map +1 -0
  37. package/dist/drivers/atk/hid.js +1368 -0
  38. package/dist/drivers/atk/hid.js.map +1 -0
  39. package/dist/drivers/atk/products.d.ts +13 -0
  40. package/dist/drivers/atk/products.d.ts.map +1 -0
  41. package/dist/drivers/atk/products.js +13 -0
  42. package/dist/drivers/atk/products.js.map +1 -0
  43. package/dist/drivers/attackshark/dpi.d.ts +41 -0
  44. package/dist/drivers/attackshark/dpi.d.ts.map +1 -0
  45. package/dist/drivers/attackshark/dpi.js +215 -0
  46. package/dist/drivers/attackshark/dpi.js.map +1 -0
  47. package/dist/drivers/attackshark/hid.d.ts +124 -0
  48. package/dist/drivers/attackshark/hid.d.ts.map +1 -0
  49. package/dist/drivers/attackshark/hid.js +728 -0
  50. package/dist/drivers/attackshark/hid.js.map +1 -0
  51. package/dist/drivers/corsair/hid.d.ts +70 -0
  52. package/dist/drivers/corsair/hid.d.ts.map +1 -0
  53. package/dist/drivers/corsair/hid.js +414 -0
  54. package/dist/drivers/corsair/hid.js.map +1 -0
  55. package/dist/drivers/dareu/hid.d.ts +59 -0
  56. package/dist/drivers/dareu/hid.d.ts.map +1 -0
  57. package/dist/drivers/dareu/hid.js +478 -0
  58. package/dist/drivers/dareu/hid.js.map +1 -0
  59. package/dist/drivers/endgame/egg-op1-hid.d.ts +107 -0
  60. package/dist/drivers/endgame/egg-op1-hid.d.ts.map +1 -0
  61. package/dist/drivers/endgame/egg-op1-hid.js +605 -0
  62. package/dist/drivers/endgame/egg-op1-hid.js.map +1 -0
  63. package/dist/drivers/endgame/egg-we-control.d.ts +42 -0
  64. package/dist/drivers/endgame/egg-we-control.d.ts.map +1 -0
  65. package/dist/drivers/endgame/egg-we-control.js +87 -0
  66. package/dist/drivers/endgame/egg-we-control.js.map +1 -0
  67. package/dist/drivers/endgame/egg-we-hid.d.ts +58 -0
  68. package/dist/drivers/endgame/egg-we-hid.d.ts.map +1 -0
  69. package/dist/drivers/endgame/egg-we-hid.js +514 -0
  70. package/dist/drivers/endgame/egg-we-hid.js.map +1 -0
  71. package/dist/drivers/fantech/hid.d.ts +106 -0
  72. package/dist/drivers/fantech/hid.d.ts.map +1 -0
  73. package/dist/drivers/fantech/hid.js +295 -0
  74. package/dist/drivers/fantech/hid.js.map +1 -0
  75. package/dist/drivers/finalmouse/hid.d.ts +31 -0
  76. package/dist/drivers/finalmouse/hid.d.ts.map +1 -0
  77. package/dist/drivers/finalmouse/hid.js +181 -0
  78. package/dist/drivers/finalmouse/hid.js.map +1 -0
  79. package/dist/drivers/gearhub/hid.d.ts +191 -0
  80. package/dist/drivers/gearhub/hid.d.ts.map +1 -0
  81. package/dist/drivers/gearhub/hid.js +542 -0
  82. package/dist/drivers/gearhub/hid.js.map +1 -0
  83. package/dist/drivers/glorious/classic-hid.d.ts +62 -0
  84. package/dist/drivers/glorious/classic-hid.d.ts.map +1 -0
  85. package/dist/drivers/glorious/classic-hid.js +326 -0
  86. package/dist/drivers/glorious/classic-hid.js.map +1 -0
  87. package/dist/drivers/glorious/hid.d.ts +39 -0
  88. package/dist/drivers/glorious/hid.d.ts.map +1 -0
  89. package/dist/drivers/glorious/hid.js +203 -0
  90. package/dist/drivers/glorious/hid.js.map +1 -0
  91. package/dist/drivers/gwolves/hid.d.ts +27 -0
  92. package/dist/drivers/gwolves/hid.d.ts.map +1 -0
  93. package/dist/drivers/gwolves/hid.js +225 -0
  94. package/dist/drivers/gwolves/hid.js.map +1 -0
  95. package/dist/drivers/gwolves/products.d.ts +17 -0
  96. package/dist/drivers/gwolves/products.d.ts.map +1 -0
  97. package/dist/drivers/gwolves/products.js +58 -0
  98. package/dist/drivers/gwolves/products.js.map +1 -0
  99. package/dist/drivers/hyperx/hid.d.ts +59 -0
  100. package/dist/drivers/hyperx/hid.d.ts.map +1 -0
  101. package/dist/drivers/hyperx/hid.js +229 -0
  102. package/dist/drivers/hyperx/hid.js.map +1 -0
  103. package/dist/drivers/incott/hid.d.ts +513 -0
  104. package/dist/drivers/incott/hid.d.ts.map +1 -0
  105. package/dist/drivers/incott/hid.js +1173 -0
  106. package/dist/drivers/incott/hid.js.map +1 -0
  107. package/dist/drivers/index.d.ts +5 -0
  108. package/dist/drivers/index.d.ts.map +1 -0
  109. package/dist/drivers/index.js +5 -0
  110. package/dist/drivers/index.js.map +1 -0
  111. package/dist/drivers/keychron/m6-hid.d.ts +81 -0
  112. package/dist/drivers/keychron/m6-hid.d.ts.map +1 -0
  113. package/dist/drivers/keychron/m6-hid.js +486 -0
  114. package/dist/drivers/keychron/m6-hid.js.map +1 -0
  115. package/dist/drivers/keychron/nape-hid.d.ts +60 -0
  116. package/dist/drivers/keychron/nape-hid.d.ts.map +1 -0
  117. package/dist/drivers/keychron/nape-hid.js +432 -0
  118. package/dist/drivers/keychron/nape-hid.js.map +1 -0
  119. package/dist/drivers/ksnake/hid.d.ts +74 -0
  120. package/dist/drivers/ksnake/hid.d.ts.map +1 -0
  121. package/dist/drivers/ksnake/hid.js +368 -0
  122. package/dist/drivers/ksnake/hid.js.map +1 -0
  123. package/dist/drivers/lamzu/hid.d.ts +58 -0
  124. package/dist/drivers/lamzu/hid.d.ts.map +1 -0
  125. package/dist/drivers/lamzu/hid.js +414 -0
  126. package/dist/drivers/lamzu/hid.js.map +1 -0
  127. package/dist/drivers/lamzu-atlantis/hid.d.ts +148 -0
  128. package/dist/drivers/lamzu-atlantis/hid.d.ts.map +1 -0
  129. package/dist/drivers/lamzu-atlantis/hid.js +587 -0
  130. package/dist/drivers/lamzu-atlantis/hid.js.map +1 -0
  131. package/dist/drivers/logitech/bolt.d.ts +41 -0
  132. package/dist/drivers/logitech/bolt.d.ts.map +1 -0
  133. package/dist/drivers/logitech/bolt.js +105 -0
  134. package/dist/drivers/logitech/bolt.js.map +1 -0
  135. package/dist/drivers/logitech/hidpp.d.ts +525 -0
  136. package/dist/drivers/logitech/hidpp.d.ts.map +1 -0
  137. package/dist/drivers/logitech/hidpp.js +2774 -0
  138. package/dist/drivers/logitech/hidpp.js.map +1 -0
  139. package/dist/drivers/logitech/mode-status.d.ts +53 -0
  140. package/dist/drivers/logitech/mode-status.d.ts.map +1 -0
  141. package/dist/drivers/logitech/mode-status.js +52 -0
  142. package/dist/drivers/logitech/mode-status.js.map +1 -0
  143. package/dist/drivers/logitech/onboard-profiles.d.ts +298 -0
  144. package/dist/drivers/logitech/onboard-profiles.d.ts.map +1 -0
  145. package/dist/drivers/logitech/onboard-profiles.js +965 -0
  146. package/dist/drivers/logitech/onboard-profiles.js.map +1 -0
  147. package/dist/drivers/logitech/rgb-effects.d.ts +20 -0
  148. package/dist/drivers/logitech/rgb-effects.d.ts.map +1 -0
  149. package/dist/drivers/logitech/rgb-effects.js +93 -0
  150. package/dist/drivers/logitech/rgb-effects.js.map +1 -0
  151. package/dist/drivers/mchose/a5-gen1-hid.d.ts +36 -0
  152. package/dist/drivers/mchose/a5-gen1-hid.d.ts.map +1 -0
  153. package/dist/drivers/mchose/a5-gen1-hid.js +219 -0
  154. package/dist/drivers/mchose/a5-gen1-hid.js.map +1 -0
  155. package/dist/drivers/mchose/dock-hid.d.ts +26 -0
  156. package/dist/drivers/mchose/dock-hid.d.ts.map +1 -0
  157. package/dist/drivers/mchose/dock-hid.js +176 -0
  158. package/dist/drivers/mchose/dock-hid.js.map +1 -0
  159. package/dist/drivers/mchose/hid.d.ts +118 -0
  160. package/dist/drivers/mchose/hid.d.ts.map +1 -0
  161. package/dist/drivers/mchose/hid.js +550 -0
  162. package/dist/drivers/mchose/hid.js.map +1 -0
  163. package/dist/drivers/mchose/v3-hid.d.ts +109 -0
  164. package/dist/drivers/mchose/v3-hid.d.ts.map +1 -0
  165. package/dist/drivers/mchose/v3-hid.js +572 -0
  166. package/dist/drivers/mchose/v3-hid.js.map +1 -0
  167. package/dist/drivers/microsoft/hid.d.ts +25 -0
  168. package/dist/drivers/microsoft/hid.d.ts.map +1 -0
  169. package/dist/drivers/microsoft/hid.js +247 -0
  170. package/dist/drivers/microsoft/hid.js.map +1 -0
  171. package/dist/drivers/moddo/hid.d.ts +31 -0
  172. package/dist/drivers/moddo/hid.d.ts.map +1 -0
  173. package/dist/drivers/moddo/hid.js +154 -0
  174. package/dist/drivers/moddo/hid.js.map +1 -0
  175. package/dist/drivers/mouse-types.d.ts +388 -0
  176. package/dist/drivers/mouse-types.d.ts.map +1 -0
  177. package/dist/drivers/mouse-types.js +2 -0
  178. package/dist/drivers/mouse-types.js.map +1 -0
  179. package/dist/drivers/ninjutso/hid.d.ts +62 -0
  180. package/dist/drivers/ninjutso/hid.d.ts.map +1 -0
  181. package/dist/drivers/ninjutso/hid.js +680 -0
  182. package/dist/drivers/ninjutso/hid.js.map +1 -0
  183. package/dist/drivers/orbital/hid.d.ts +24 -0
  184. package/dist/drivers/orbital/hid.d.ts.map +1 -0
  185. package/dist/drivers/orbital/hid.js +85 -0
  186. package/dist/drivers/orbital/hid.js.map +1 -0
  187. package/dist/drivers/orbital/host-protocol.d.ts +59 -0
  188. package/dist/drivers/orbital/host-protocol.d.ts.map +1 -0
  189. package/dist/drivers/orbital/host-protocol.js +884 -0
  190. package/dist/drivers/orbital/host-protocol.js.map +1 -0
  191. package/dist/drivers/pulsar/pulsar-hid.d.ts +63 -0
  192. package/dist/drivers/pulsar/pulsar-hid.d.ts.map +1 -0
  193. package/dist/drivers/pulsar/pulsar-hid.js +381 -0
  194. package/dist/drivers/pulsar/pulsar-hid.js.map +1 -0
  195. package/dist/drivers/pulsar/pulsar-pro-hid.d.ts +46 -0
  196. package/dist/drivers/pulsar/pulsar-pro-hid.d.ts.map +1 -0
  197. package/dist/drivers/pulsar/pulsar-pro-hid.js +343 -0
  198. package/dist/drivers/pulsar/pulsar-pro-hid.js.map +1 -0
  199. package/dist/drivers/pulsar/pulsar-xs1-hid.d.ts +40 -0
  200. package/dist/drivers/pulsar/pulsar-xs1-hid.d.ts.map +1 -0
  201. package/dist/drivers/pulsar/pulsar-xs1-hid.js +251 -0
  202. package/dist/drivers/pulsar/pulsar-xs1-hid.js.map +1 -0
  203. package/dist/drivers/rawm/hid.d.ts +29 -0
  204. package/dist/drivers/rawm/hid.d.ts.map +1 -0
  205. package/dist/drivers/rawm/hid.js +210 -0
  206. package/dist/drivers/rawm/hid.js.map +1 -0
  207. package/dist/drivers/razer/cobra-hid.d.ts +63 -0
  208. package/dist/drivers/razer/cobra-hid.d.ts.map +1 -0
  209. package/dist/drivers/razer/cobra-hid.js +282 -0
  210. package/dist/drivers/razer/cobra-hid.js.map +1 -0
  211. package/dist/drivers/razer/hid-open.d.ts +13 -0
  212. package/dist/drivers/razer/hid-open.d.ts.map +1 -0
  213. package/dist/drivers/razer/hid-open.js +29 -0
  214. package/dist/drivers/razer/hid-open.js.map +1 -0
  215. package/dist/drivers/razer/hid.d.ts +231 -0
  216. package/dist/drivers/razer/hid.d.ts.map +1 -0
  217. package/dist/drivers/razer/hid.js +772 -0
  218. package/dist/drivers/razer/hid.js.map +1 -0
  219. package/dist/drivers/razer/viper-hid.d.ts +33 -0
  220. package/dist/drivers/razer/viper-hid.d.ts.map +1 -0
  221. package/dist/drivers/razer/viper-hid.js +177 -0
  222. package/dist/drivers/razer/viper-hid.js.map +1 -0
  223. package/dist/drivers/razer/viper-mini-hid.d.ts +58 -0
  224. package/dist/drivers/razer/viper-mini-hid.d.ts.map +1 -0
  225. package/dist/drivers/razer/viper-mini-hid.js +273 -0
  226. package/dist/drivers/razer/viper-mini-hid.js.map +1 -0
  227. package/dist/drivers/razer/viper-v4-pro-hid.d.ts +26 -0
  228. package/dist/drivers/razer/viper-v4-pro-hid.d.ts.map +1 -0
  229. package/dist/drivers/razer/viper-v4-pro-hid.js +154 -0
  230. package/dist/drivers/razer/viper-v4-pro-hid.js.map +1 -0
  231. package/dist/drivers/registry.d.ts +70 -0
  232. package/dist/drivers/registry.d.ts.map +1 -0
  233. package/dist/drivers/registry.js +146 -0
  234. package/dist/drivers/registry.js.map +1 -0
  235. package/dist/drivers/steelseries/aerox3-hid.d.ts +53 -0
  236. package/dist/drivers/steelseries/aerox3-hid.d.ts.map +1 -0
  237. package/dist/drivers/steelseries/aerox3-hid.js +172 -0
  238. package/dist/drivers/steelseries/aerox3-hid.js.map +1 -0
  239. package/dist/drivers/steelseries/aerox5-hid.d.ts +54 -0
  240. package/dist/drivers/steelseries/aerox5-hid.d.ts.map +1 -0
  241. package/dist/drivers/steelseries/aerox5-hid.js +173 -0
  242. package/dist/drivers/steelseries/aerox5-hid.js.map +1 -0
  243. package/dist/drivers/steelseries/aerox5-wireless-hid.d.ts +69 -0
  244. package/dist/drivers/steelseries/aerox5-wireless-hid.d.ts.map +1 -0
  245. package/dist/drivers/steelseries/aerox5-wireless-hid.js +234 -0
  246. package/dist/drivers/steelseries/aerox5-wireless-hid.js.map +1 -0
  247. package/dist/drivers/steelseries/aerox9-wireless-hid.d.ts +70 -0
  248. package/dist/drivers/steelseries/aerox9-wireless-hid.d.ts.map +1 -0
  249. package/dist/drivers/steelseries/aerox9-wireless-hid.js +227 -0
  250. package/dist/drivers/steelseries/aerox9-wireless-hid.js.map +1 -0
  251. package/dist/drivers/steelseries/hid.d.ts +48 -0
  252. package/dist/drivers/steelseries/hid.d.ts.map +1 -0
  253. package/dist/drivers/steelseries/hid.js +157 -0
  254. package/dist/drivers/steelseries/hid.js.map +1 -0
  255. package/dist/drivers/steelseries/prime-mini-wireless-hid.d.ts +62 -0
  256. package/dist/drivers/steelseries/prime-mini-wireless-hid.d.ts.map +1 -0
  257. package/dist/drivers/steelseries/prime-mini-wireless-hid.js +215 -0
  258. package/dist/drivers/steelseries/prime-mini-wireless-hid.js.map +1 -0
  259. package/dist/drivers/steelseries/prime-plus-hid.d.ts +51 -0
  260. package/dist/drivers/steelseries/prime-plus-hid.d.ts.map +1 -0
  261. package/dist/drivers/steelseries/prime-plus-hid.js +150 -0
  262. package/dist/drivers/steelseries/prime-plus-hid.js.map +1 -0
  263. package/dist/drivers/steelseries/rival3-wireless-hid.d.ts +61 -0
  264. package/dist/drivers/steelseries/rival3-wireless-hid.d.ts.map +1 -0
  265. package/dist/drivers/steelseries/rival3-wireless-hid.js +185 -0
  266. package/dist/drivers/steelseries/rival3-wireless-hid.js.map +1 -0
  267. package/dist/drivers/steelseries/rival310-hid.d.ts +59 -0
  268. package/dist/drivers/steelseries/rival310-hid.d.ts.map +1 -0
  269. package/dist/drivers/steelseries/rival310-hid.js +182 -0
  270. package/dist/drivers/steelseries/rival310-hid.js.map +1 -0
  271. package/dist/drivers/steelseries/rival650-hid.d.ts +68 -0
  272. package/dist/drivers/steelseries/rival650-hid.d.ts.map +1 -0
  273. package/dist/drivers/steelseries/rival650-hid.js +209 -0
  274. package/dist/drivers/steelseries/rival650-hid.js.map +1 -0
  275. package/dist/drivers/steelseries/sensei-ten-hid.d.ts +62 -0
  276. package/dist/drivers/steelseries/sensei-ten-hid.d.ts.map +1 -0
  277. package/dist/drivers/steelseries/sensei-ten-hid.js +186 -0
  278. package/dist/drivers/steelseries/sensei-ten-hid.js.map +1 -0
  279. package/dist/drivers/teevolution/hid.d.ts +82 -0
  280. package/dist/drivers/teevolution/hid.d.ts.map +1 -0
  281. package/dist/drivers/teevolution/hid.js +607 -0
  282. package/dist/drivers/teevolution/hid.js.map +1 -0
  283. package/dist/drivers/vendors.d.ts +254 -0
  284. package/dist/drivers/vendors.d.ts.map +1 -0
  285. package/dist/drivers/vendors.js +587 -0
  286. package/dist/drivers/vendors.js.map +1 -0
  287. package/dist/drivers/vgn/hid.d.ts +33 -0
  288. package/dist/drivers/vgn/hid.d.ts.map +1 -0
  289. package/dist/drivers/vgn/hid.js +213 -0
  290. package/dist/drivers/vgn/hid.js.map +1 -0
  291. package/dist/drivers/wallhack/keyboard-hid.d.ts +28 -0
  292. package/dist/drivers/wallhack/keyboard-hid.d.ts.map +1 -0
  293. package/dist/drivers/wallhack/keyboard-hid.js +80 -0
  294. package/dist/drivers/wallhack/keyboard-hid.js.map +1 -0
  295. package/dist/drivers/wallhack/mouse-hid.d.ts +45 -0
  296. package/dist/drivers/wallhack/mouse-hid.d.ts.map +1 -0
  297. package/dist/drivers/wallhack/mouse-hid.js +288 -0
  298. package/dist/drivers/wallhack/mouse-hid.js.map +1 -0
  299. package/dist/drivers/webhid.d.ts +59 -0
  300. package/dist/drivers/webhid.d.ts.map +1 -0
  301. package/dist/drivers/webhid.js +2 -0
  302. package/dist/drivers/webhid.js.map +1 -0
  303. package/dist/drivers/wlmouse/hid.d.ts +81 -0
  304. package/dist/drivers/wlmouse/hid.d.ts.map +1 -0
  305. package/dist/drivers/wlmouse/hid.js +576 -0
  306. package/dist/drivers/wlmouse/hid.js.map +1 -0
  307. package/dist/drivers/wooting/hid.d.ts +86 -0
  308. package/dist/drivers/wooting/hid.d.ts.map +1 -0
  309. package/dist/drivers/wooting/hid.js +320 -0
  310. package/dist/drivers/wooting/hid.js.map +1 -0
  311. package/dist/drivers/zaunkoenig/hid.d.ts +31 -0
  312. package/dist/drivers/zaunkoenig/hid.d.ts.map +1 -0
  313. package/dist/drivers/zaunkoenig/hid.js +162 -0
  314. package/dist/drivers/zaunkoenig/hid.js.map +1 -0
  315. package/dist/endgame-gear/op1.d.ts +165 -0
  316. package/dist/endgame-gear/op1.d.ts.map +1 -0
  317. package/dist/endgame-gear/op1.js +384 -0
  318. package/dist/endgame-gear/op1.js.map +1 -0
  319. package/dist/endgame-gear/wireless.d.ts +93 -0
  320. package/dist/endgame-gear/wireless.d.ts.map +1 -0
  321. package/dist/endgame-gear/wireless.js +242 -0
  322. package/dist/endgame-gear/wireless.js.map +1 -0
  323. package/dist/fantech/index.d.ts +9 -0
  324. package/dist/fantech/index.d.ts.map +1 -0
  325. package/dist/fantech/index.js +11 -0
  326. package/dist/fantech/index.js.map +1 -0
  327. package/dist/finalmouse/index.d.ts +41 -0
  328. package/dist/finalmouse/index.d.ts.map +1 -0
  329. package/dist/finalmouse/index.js +106 -0
  330. package/dist/finalmouse/index.js.map +1 -0
  331. package/dist/gearhub/index.d.ts +210 -0
  332. package/dist/gearhub/index.d.ts.map +1 -0
  333. package/dist/gearhub/index.js +282 -0
  334. package/dist/gearhub/index.js.map +1 -0
  335. package/dist/glorious/index.d.ts +89 -0
  336. package/dist/glorious/index.d.ts.map +1 -0
  337. package/dist/glorious/index.js +236 -0
  338. package/dist/glorious/index.js.map +1 -0
  339. package/dist/glorious-classic/index.d.ts +103 -0
  340. package/dist/glorious-classic/index.d.ts.map +1 -0
  341. package/dist/glorious-classic/index.js +304 -0
  342. package/dist/glorious-classic/index.js.map +1 -0
  343. package/dist/gwolves/index.d.ts +82 -0
  344. package/dist/gwolves/index.d.ts.map +1 -0
  345. package/dist/gwolves/index.js +197 -0
  346. package/dist/gwolves/index.js.map +1 -0
  347. package/dist/hyperx/index.d.ts +181 -0
  348. package/dist/hyperx/index.d.ts.map +1 -0
  349. package/dist/hyperx/index.js +303 -0
  350. package/dist/hyperx/index.js.map +1 -0
  351. package/dist/incott/index.d.ts +1067 -0
  352. package/dist/incott/index.d.ts.map +1 -0
  353. package/dist/incott/index.js +1482 -0
  354. package/dist/incott/index.js.map +1 -0
  355. package/dist/index.d.ts +30 -0
  356. package/dist/index.d.ts.map +1 -0
  357. package/dist/index.js +30 -0
  358. package/dist/index.js.map +1 -0
  359. package/dist/keychron/index.d.ts +194 -0
  360. package/dist/keychron/index.d.ts.map +1 -0
  361. package/dist/keychron/index.js +341 -0
  362. package/dist/keychron/index.js.map +1 -0
  363. package/dist/ksnake/index.d.ts +157 -0
  364. package/dist/ksnake/index.d.ts.map +1 -0
  365. package/dist/ksnake/index.js +314 -0
  366. package/dist/ksnake/index.js.map +1 -0
  367. package/dist/lamzu/atlantis.d.ts +237 -0
  368. package/dist/lamzu/atlantis.d.ts.map +1 -0
  369. package/dist/lamzu/atlantis.js +263 -0
  370. package/dist/lamzu/atlantis.js.map +1 -0
  371. package/dist/lamzu/index.d.ts +60 -0
  372. package/dist/lamzu/index.d.ts.map +1 -0
  373. package/dist/lamzu/index.js +86 -0
  374. package/dist/lamzu/index.js.map +1 -0
  375. package/dist/logitech/controls.d.ts +138 -0
  376. package/dist/logitech/controls.d.ts.map +1 -0
  377. package/dist/logitech/controls.js +184 -0
  378. package/dist/logitech/controls.js.map +1 -0
  379. package/dist/logitech/friendly-name.d.ts +50 -0
  380. package/dist/logitech/friendly-name.d.ts.map +1 -0
  381. package/dist/logitech/friendly-name.js +74 -0
  382. package/dist/logitech/friendly-name.js.map +1 -0
  383. package/dist/logitech/haptics.d.ts +97 -0
  384. package/dist/logitech/haptics.d.ts.map +1 -0
  385. package/dist/logitech/haptics.js +116 -0
  386. package/dist/logitech/haptics.js.map +1 -0
  387. package/dist/logitech/hosts.d.ts +55 -0
  388. package/dist/logitech/hosts.d.ts.map +1 -0
  389. package/dist/logitech/hosts.js +80 -0
  390. package/dist/logitech/hosts.js.map +1 -0
  391. package/dist/logitech/index.d.ts +127 -0
  392. package/dist/logitech/index.d.ts.map +1 -0
  393. package/dist/logitech/index.js +233 -0
  394. package/dist/logitech/index.js.map +1 -0
  395. package/dist/logitech/wheel.d.ts +117 -0
  396. package/dist/logitech/wheel.d.ts.map +1 -0
  397. package/dist/logitech/wheel.js +133 -0
  398. package/dist/logitech/wheel.js.map +1 -0
  399. package/dist/mchose/a5-gen1.d.ts +38 -0
  400. package/dist/mchose/a5-gen1.d.ts.map +1 -0
  401. package/dist/mchose/a5-gen1.js +60 -0
  402. package/dist/mchose/a5-gen1.js.map +1 -0
  403. package/dist/mchose/buttons.d.ts +66 -0
  404. package/dist/mchose/buttons.d.ts.map +1 -0
  405. package/dist/mchose/buttons.js +184 -0
  406. package/dist/mchose/buttons.js.map +1 -0
  407. package/dist/mchose/dock.d.ts +77 -0
  408. package/dist/mchose/dock.d.ts.map +1 -0
  409. package/dist/mchose/dock.js +133 -0
  410. package/dist/mchose/dock.js.map +1 -0
  411. package/dist/mchose/index.d.ts +299 -0
  412. package/dist/mchose/index.d.ts.map +1 -0
  413. package/dist/mchose/index.js +429 -0
  414. package/dist/mchose/index.js.map +1 -0
  415. package/dist/mchose/v3-buttons.d.ts +64 -0
  416. package/dist/mchose/v3-buttons.d.ts.map +1 -0
  417. package/dist/mchose/v3-buttons.js +258 -0
  418. package/dist/mchose/v3-buttons.js.map +1 -0
  419. package/dist/mchose/v3.d.ts +380 -0
  420. package/dist/mchose/v3.d.ts.map +1 -0
  421. package/dist/mchose/v3.js +608 -0
  422. package/dist/mchose/v3.js.map +1 -0
  423. package/dist/microsoft/index.d.ts +19 -0
  424. package/dist/microsoft/index.d.ts.map +1 -0
  425. package/dist/microsoft/index.js +22 -0
  426. package/dist/microsoft/index.js.map +1 -0
  427. package/dist/moddo/index.d.ts +72 -0
  428. package/dist/moddo/index.d.ts.map +1 -0
  429. package/dist/moddo/index.js +147 -0
  430. package/dist/moddo/index.js.map +1 -0
  431. package/dist/ninjutso/index.d.ts +74 -0
  432. package/dist/ninjutso/index.d.ts.map +1 -0
  433. package/dist/ninjutso/index.js +133 -0
  434. package/dist/ninjutso/index.js.map +1 -0
  435. package/dist/orbital/index.d.ts +14 -0
  436. package/dist/orbital/index.d.ts.map +1 -0
  437. package/dist/orbital/index.js +19 -0
  438. package/dist/orbital/index.js.map +1 -0
  439. package/dist/pulsar/index.d.ts +81 -0
  440. package/dist/pulsar/index.d.ts.map +1 -0
  441. package/dist/pulsar/index.js +185 -0
  442. package/dist/pulsar/index.js.map +1 -0
  443. package/dist/rawm/index.d.ts +55 -0
  444. package/dist/rawm/index.d.ts.map +1 -0
  445. package/dist/rawm/index.js +229 -0
  446. package/dist/rawm/index.js.map +1 -0
  447. package/dist/razer/codec.d.ts +504 -0
  448. package/dist/razer/codec.d.ts.map +1 -0
  449. package/dist/razer/codec.js +648 -0
  450. package/dist/razer/codec.js.map +1 -0
  451. package/dist/razer/devices.d.ts +156 -0
  452. package/dist/razer/devices.d.ts.map +1 -0
  453. package/dist/razer/devices.js +540 -0
  454. package/dist/razer/devices.js.map +1 -0
  455. package/dist/razer/index.d.ts +2 -0
  456. package/dist/razer/index.d.ts.map +1 -0
  457. package/dist/razer/index.js +2 -0
  458. package/dist/razer/index.js.map +1 -0
  459. package/dist/razer/v4.d.ts +19 -0
  460. package/dist/razer/v4.d.ts.map +1 -0
  461. package/dist/razer/v4.js +51 -0
  462. package/dist/razer/v4.js.map +1 -0
  463. package/dist/steelseries/aerox3.d.ts +236 -0
  464. package/dist/steelseries/aerox3.d.ts.map +1 -0
  465. package/dist/steelseries/aerox3.js +311 -0
  466. package/dist/steelseries/aerox3.js.map +1 -0
  467. package/dist/steelseries/aerox5-wireless.d.ts +300 -0
  468. package/dist/steelseries/aerox5-wireless.d.ts.map +1 -0
  469. package/dist/steelseries/aerox5-wireless.js +389 -0
  470. package/dist/steelseries/aerox5-wireless.js.map +1 -0
  471. package/dist/steelseries/aerox5.d.ts +228 -0
  472. package/dist/steelseries/aerox5.d.ts.map +1 -0
  473. package/dist/steelseries/aerox5.js +294 -0
  474. package/dist/steelseries/aerox5.js.map +1 -0
  475. package/dist/steelseries/aerox9-wireless.d.ts +213 -0
  476. package/dist/steelseries/aerox9-wireless.d.ts.map +1 -0
  477. package/dist/steelseries/aerox9-wireless.js +305 -0
  478. package/dist/steelseries/aerox9-wireless.js.map +1 -0
  479. package/dist/steelseries/devices.d.ts +82 -0
  480. package/dist/steelseries/devices.d.ts.map +1 -0
  481. package/dist/steelseries/devices.js +310 -0
  482. package/dist/steelseries/devices.js.map +1 -0
  483. package/dist/steelseries/index.d.ts +13 -0
  484. package/dist/steelseries/index.d.ts.map +1 -0
  485. package/dist/steelseries/index.js +13 -0
  486. package/dist/steelseries/index.js.map +1 -0
  487. package/dist/steelseries/prime-mini-wireless.d.ts +253 -0
  488. package/dist/steelseries/prime-mini-wireless.d.ts.map +1 -0
  489. package/dist/steelseries/prime-mini-wireless.js +351 -0
  490. package/dist/steelseries/prime-mini-wireless.js.map +1 -0
  491. package/dist/steelseries/prime-plus.d.ts +179 -0
  492. package/dist/steelseries/prime-plus.d.ts.map +1 -0
  493. package/dist/steelseries/prime-plus.js +275 -0
  494. package/dist/steelseries/prime-plus.js.map +1 -0
  495. package/dist/steelseries/rival3-wireless.d.ts +222 -0
  496. package/dist/steelseries/rival3-wireless.d.ts.map +1 -0
  497. package/dist/steelseries/rival3-wireless.js +308 -0
  498. package/dist/steelseries/rival3-wireless.js.map +1 -0
  499. package/dist/steelseries/rival3.d.ts +99 -0
  500. package/dist/steelseries/rival3.d.ts.map +1 -0
  501. package/dist/steelseries/rival3.js +147 -0
  502. package/dist/steelseries/rival3.js.map +1 -0
  503. package/dist/steelseries/rival310.d.ts +230 -0
  504. package/dist/steelseries/rival310.d.ts.map +1 -0
  505. package/dist/steelseries/rival310.js +322 -0
  506. package/dist/steelseries/rival310.js.map +1 -0
  507. package/dist/steelseries/rival650.d.ts +215 -0
  508. package/dist/steelseries/rival650.d.ts.map +1 -0
  509. package/dist/steelseries/rival650.js +284 -0
  510. package/dist/steelseries/rival650.js.map +1 -0
  511. package/dist/steelseries/sensei-ten.d.ts +283 -0
  512. package/dist/steelseries/sensei-ten.d.ts.map +1 -0
  513. package/dist/steelseries/sensei-ten.js +389 -0
  514. package/dist/steelseries/sensei-ten.js.map +1 -0
  515. package/dist/teevolution/index.d.ts +211 -0
  516. package/dist/teevolution/index.d.ts.map +1 -0
  517. package/dist/teevolution/index.js +458 -0
  518. package/dist/teevolution/index.js.map +1 -0
  519. package/dist/valkyrie/index.d.ts +19 -0
  520. package/dist/valkyrie/index.d.ts.map +1 -0
  521. package/dist/valkyrie/index.js +43 -0
  522. package/dist/valkyrie/index.js.map +1 -0
  523. package/dist/valkyrie/settings.d.ts +28 -0
  524. package/dist/valkyrie/settings.d.ts.map +1 -0
  525. package/dist/valkyrie/settings.js +84 -0
  526. package/dist/valkyrie/settings.js.map +1 -0
  527. package/dist/vgn/index.d.ts +59 -0
  528. package/dist/vgn/index.d.ts.map +1 -0
  529. package/dist/vgn/index.js +165 -0
  530. package/dist/vgn/index.js.map +1 -0
  531. package/dist/wallhack/index.d.ts +165 -0
  532. package/dist/wallhack/index.d.ts.map +1 -0
  533. package/dist/wallhack/index.js +226 -0
  534. package/dist/wallhack/index.js.map +1 -0
  535. package/dist/wlmouse/index.d.ts +4 -0
  536. package/dist/wlmouse/index.d.ts.map +1 -0
  537. package/dist/wlmouse/index.js +7 -0
  538. package/dist/wlmouse/index.js.map +1 -0
  539. package/dist/wooting/index.d.ts +225 -0
  540. package/dist/wooting/index.d.ts.map +1 -0
  541. package/dist/wooting/index.js +296 -0
  542. package/dist/wooting/index.js.map +1 -0
  543. package/dist/zaunkoenig/index.d.ts +49 -0
  544. package/dist/zaunkoenig/index.d.ts.map +1 -0
  545. package/dist/zaunkoenig/index.js +127 -0
  546. package/dist/zaunkoenig/index.js.map +1 -0
  547. package/package.json +193 -0
@@ -0,0 +1,884 @@
1
+ import { ORBITAL_DEVICES, ORBITAL_PACKET_SIZE, ORBITAL_REPORT_ID, ORBITAL_REPORT_RATES_HZ, ORBITAL_VENDOR_ID, orbitalFinishPacket, } from "@openmouse/protocol/orbital";
2
+ /**
3
+ * Orbital mouse host protocol
4
+ *
5
+ * Plain JavaScript. No UI, no HTML, no CSS, no images and no build step.
6
+ *
7
+ * This is the host-side HID protocol used by the Orbital control app. It is not
8
+ * mouse firmware. The useful part for another project is the packet layout,
9
+ * parsers and write flow. The small HID transport layer can be replaced.
10
+ *
11
+ * What is covered here:
12
+ * - wired mouse and wireless receiver routing
13
+ * - DMS v1 and DMS v2 detection
14
+ * - battery, charging state and live status packets
15
+ * - five onboard profiles
16
+ * - five X/Y DPI stages, enabled-stage mask and active stage
17
+ * - polling rate
18
+ * - lift-off-distance level
19
+ * - angle tune and angle snapping
20
+ * - Motion Sync and ripple control
21
+ * - high-performance and full-speed/overclock modes
22
+ * - debounce, quick response, wheel reverse and sleep time
23
+ * - saving settings and factory reset
24
+ *
25
+ * Deliberately not included:
26
+ * - button remapping
27
+ * - macros
28
+ * - mouse or receiver lighting
29
+ *
30
+ * ---------------------------------------------------------------------------
31
+ * QUICK USE
32
+ * ---------------------------------------------------------------------------
33
+ *
34
+ * Browser/WebHID:
35
+ *
36
+ * const client = await OrbitalMouseClient.requestFromBrowser({
37
+ * logger: (message, bytes) => console.log(message, bytes),
38
+ * });
39
+ *
40
+ * await client.open();
41
+ * console.log(await client.readEverything());
42
+ *
43
+ * await client.applySettings({
44
+ * dpiStages: [[400, 400], [800, 800], [1600, 1600], [3200, 3200], [6400, 6400]],
45
+ * activeDpiStage: 1,
46
+ * reportRateIndex: reportRateHzToIndex(1000),
47
+ * liftOffDistance: 0,
48
+ * angleTuning: 0,
49
+ * motionSync: true,
50
+ * highPerformance: true,
51
+ * });
52
+ *
53
+ * Electron or another HID library:
54
+ *
55
+ * Wrap its device so it exposes:
56
+ * vendorId, productId, productName, opened, collections,
57
+ * open(), close(), sendReport(), addEventListener(), removeEventListener()
58
+ *
59
+ * Then pass it directly:
60
+ * const client = new OrbitalMouseClient(myWrappedDevice);
61
+ *
62
+ * ---------------------------------------------------------------------------
63
+ * PACKET SHAPE
64
+ * ---------------------------------------------------------------------------
65
+ *
66
+ * Every config packet is 64 bytes:
67
+ *
68
+ * byte 0 command family
69
+ * bit 6 (0x40) means "route this through the receiver to the mouse"
70
+ * byte 2 command/opcode
71
+ * byte 3 subcommand
72
+ * bytes 4..62 payload
73
+ * byte 63 checksum: (0xA1 - sum(bytes 0..62)) & 0xFF
74
+ *
75
+ * Replies routed through the receiver usually have byte 0 with 0x40 added.
76
+ * That is why the response checks accept values such as 4 or 68 (0x44).
77
+ *
78
+ * Settings writes are followed by the save command. A reply only confirms that
79
+ * the packet arrived, so applySettings() reads everything back afterward.
80
+ *
81
+ * ---------------------------------------------------------------------------
82
+ * SETTING NAMES THAT ARE EASY TO MISREAD
83
+ * ---------------------------------------------------------------------------
84
+ *
85
+ * liftOffDistance 0, 1 or 2. These are the mouse's three LOD levels, not mm.
86
+ * angleTuning fixed report-axis rotation in signed degrees (-30..+30).
87
+ * It does not measure live physical mouse rotation.
88
+ * highPerformance maps to the device field called maxSpeedMode.
89
+ * overclockedMode maps to the device field called fullSpeedMode.
90
+ * quickResponse DMS v2 system setting. V1 reports false here.
91
+ * dpiStages always five [x, y] pairs. X and Y may be different.
92
+ * enabledDpiStages how many stages from the start are enabled (1..5).
93
+ * activeDpiStage zero-based stage number (0..4).
94
+ * reportRateIndex index into ORBITAL_REPORT_RATES_HZ, not literal hertz.
95
+ *
96
+ * The original app's supported rate table is kept exactly as found:
97
+ * 125, 500, 1000, 2000, 4000 and 8000 Hz.
98
+ * Raw rate value 1 is skipped by the app's encoding, so this file does not guess
99
+ * that it means 250 Hz.
100
+ *
101
+ * Some v2 system bytes describe wake behavior and internal button modes. They are
102
+ * read and preserved when writing, but are not exposed as editable controls here.
103
+ * Zeroing those pass-through bytes could change unrelated device behavior.
104
+ */
105
+ /**
106
+ * @typedef {[number, number]} DpiPair
107
+ * X DPI followed by Y DPI.
108
+ */
109
+ /**
110
+ * @typedef {[number, number, number]} Rgb
111
+ * Preserved DPI-stage color from the device. Lighting control is not implemented.
112
+ */
113
+ /**
114
+ * @typedef {Object} OrbitalEditableSettings
115
+ * @property {DpiPair[]} dpiStages Five X/Y DPI pairs.
116
+ * @property {number} enabledDpiStages Number of enabled stages, 1 through 5.
117
+ * @property {number} activeDpiStage Zero-based active stage, 0 through 4.
118
+ * @property {number} reportRateIndex Index into ORBITAL_REPORT_RATES_HZ.
119
+ * @property {number} sleepSeconds Sleep timeout stored by the device.
120
+ * @property {number} debounceMs Debounce value in milliseconds.
121
+ * @property {number} liftOffDistance Device LOD level: 0, 1 or 2.
122
+ * @property {number} angleTuning Fixed angle correction in signed degrees.
123
+ * @property {boolean} angleSnapping
124
+ * @property {boolean} rippleControl
125
+ * @property {boolean} motionSync
126
+ * @property {boolean} highPerformance Device maxSpeedMode.
127
+ * @property {boolean} overclockedMode Device fullSpeedMode.
128
+ * @property {boolean} quickResponse DMS v2 only.
129
+ * @property {boolean} wheelReverse
130
+ */
131
+ // -----------------------------------------------------------------------------
132
+ // Public constants
133
+ // -----------------------------------------------------------------------------
134
+ const ORBITAL_PROFILE_COUNT = 5;
135
+ const ORBITAL_DPI_LIMITS = { min: 50, max: 30000, step: 50 };
136
+ // -----------------------------------------------------------------------------
137
+ // Main client
138
+ // -----------------------------------------------------------------------------
139
+ class OrbitalMouseClient {
140
+ constructor(device, options = {}) {
141
+ this.identity = null;
142
+ this.settings = null;
143
+ this.waiters = new Set();
144
+ this.updateListeners = new Set();
145
+ this.handleInputReportBound = (event) => this.handleInputReport(event);
146
+ this.handleDisconnectBound = () => this.handleDisconnect();
147
+ const definition = ORBITAL_DEVICES.get(device.productId);
148
+ if (device.vendorId !== ORBITAL_VENDOR_ID || !definition) {
149
+ throw new Error(`Unsupported Orbital device 0x${device.vendorId.toString(16)}:0x${device.productId.toString(16)}`);
150
+ }
151
+ this.device = device;
152
+ this.definition = definition;
153
+ this.protocol = definition.protocol;
154
+ this.isReceiver = definition.receiver;
155
+ this.timeoutMs = options.timeoutMs ?? 1800;
156
+ this.logger = options.logger ?? (() => undefined);
157
+ }
158
+ /**
159
+ * Browser helper. Electron can ignore this and pass its own device to the constructor.
160
+ */
161
+ static async requestFromBrowser(options = {}) {
162
+ const hid = globalThis.navigator?.hid;
163
+ if (!hid)
164
+ throw new Error("WebHID is not available in this browser.");
165
+ const selected = await hid.requestDevice({
166
+ filters: Array.from(ORBITAL_DEVICES.keys(), (productId) => ({
167
+ vendorId: ORBITAL_VENDOR_ID,
168
+ productId,
169
+ // This narrows Chromium down to the vendor configuration interface.
170
+ usagePage: 0xff0a,
171
+ usage: 1,
172
+ })),
173
+ });
174
+ // Composite HID devices sometimes appear more than once. Prefer the collection
175
+ // that actually carries the DMS config protocol.
176
+ const device = selected.find(hasOrbitalConfigCollection) ?? selected[0];
177
+ if (!device)
178
+ throw new Error("No Orbital device was selected.");
179
+ return new OrbitalMouseClient(device, options);
180
+ }
181
+ async open(readInitialState = true) {
182
+ if (!hasOrbitalConfigCollection(this.device)) {
183
+ throw new Error("This HID entry does not expose the Orbital config collection.");
184
+ }
185
+ if (!this.device.opened)
186
+ await this.device.open();
187
+ this.device.addEventListener("inputreport", this.handleInputReportBound);
188
+ this.device.addEventListener("disconnect", this.handleDisconnectBound);
189
+ try {
190
+ const identity = await this.detectProtocol();
191
+ if (readInitialState) {
192
+ this.settings = await this.readSettings();
193
+ try {
194
+ this.settings.power = await this.readPower();
195
+ }
196
+ catch (error) {
197
+ this.logger(`Battery read skipped: ${errorMessage(error)}`);
198
+ }
199
+ }
200
+ return identity;
201
+ }
202
+ catch (error) {
203
+ await this.close();
204
+ throw error;
205
+ }
206
+ }
207
+ async close() {
208
+ this.rejectAllWaiters(new Error("Device disconnected."));
209
+ this.device.removeEventListener("inputreport", this.handleInputReportBound);
210
+ this.device.removeEventListener("disconnect", this.handleDisconnectBound);
211
+ if (this.device.opened) {
212
+ try {
213
+ await this.device.close();
214
+ }
215
+ catch {
216
+ // Closing an already-disconnected HID device throws in a few Chromium builds.
217
+ }
218
+ }
219
+ }
220
+ onLiveUpdate(listener) {
221
+ this.updateListeners.add(listener);
222
+ return () => this.updateListeners.delete(listener);
223
+ }
224
+ /**
225
+ * Reads the useful device/settings state in one go.
226
+ *
227
+ * I left button maps, macros and lighting out of this handoff. This keeps the
228
+ * file focused on profiles, DPI and the sensor/system settings OpenMouse needs.
229
+ */
230
+ async readEverything() {
231
+ const identity = this.identity ?? await this.detectProtocol();
232
+ const settings = await this.readSettings();
233
+ const power = await this.readPower();
234
+ settings.power = power;
235
+ this.settings = settings;
236
+ return { identity, settings, power };
237
+ }
238
+ // ---------------------------------------------------------------------------
239
+ // Identity / basic status
240
+ // ---------------------------------------------------------------------------
241
+ /**
242
+ * Handshake packet:
243
+ * [0] = 0x01, [2] = 0x81, [3] = 0x01
244
+ *
245
+ * This command targets the HID device itself. For a receiver we intentionally
246
+ * do not set the route bit, because the reply contains receiver/pairing info.
247
+ */
248
+ async detectProtocol() {
249
+ const packet = this.makePacket();
250
+ packet[0] = 1;
251
+ packet[2] = 129;
252
+ packet[3] = 1;
253
+ // This handshake is sent to the HID device itself. When the HID device is the
254
+ // receiver, routing it through to the mouse would give us the wrong identity.
255
+ this.finishPacket(packet, false);
256
+ const response = await this.requestResponse(packet, (bytes) => bytes[0] === 1, "protocol handshake", 2500);
257
+ let pairedVendorId;
258
+ let pairedProductId;
259
+ if (this.isReceiver && this.protocol === "dms_v2") {
260
+ pairedVendorId = response[6] | (response[7] << 8);
261
+ pairedProductId = response[8] | (response[9] << 8);
262
+ if (pairedVendorId !== ORBITAL_VENDOR_ID ||
263
+ pairedProductId !== this.definition.pairedProductId) {
264
+ throw new Error(`Receiver is paired to 0x${toHex4(pairedVendorId)}:0x${toHex4(pairedProductId)}, not the expected mouse.`);
265
+ }
266
+ }
267
+ const identity = {
268
+ vendorId: this.device.vendorId,
269
+ productId: this.device.productId,
270
+ productName: this.device.productName || this.definition.name,
271
+ definition: this.definition,
272
+ connection: this.isReceiver ? "wireless" : "wired",
273
+ pairedVendorId,
274
+ pairedProductId,
275
+ rawHandshake: response,
276
+ };
277
+ this.identity = identity;
278
+ return identity;
279
+ }
280
+ /**
281
+ * Reads battery state, percentage and current onboard profile.
282
+ * The offsets differ between DMS v1 and DMS v2, so this normalizes both into
283
+ * { state, percent, profile }.
284
+ */
285
+ async readPower() {
286
+ const packet = this.packetWith([0, 1], [2, 129], [3, 1]);
287
+ const response = await this.requestResponse(packet, (bytes) => (bytes[0] === 1 || bytes[0] === 65) && bytes[3] === 1, "read battery");
288
+ const stateOffset = this.protocol === "dms_v2" ? 10 : 5;
289
+ const percentOffset = this.protocol === "dms_v2" ? 11 : 6;
290
+ const profileOffset = this.protocol === "dms_v2" ? 12 : 7;
291
+ const rawState = response[stateOffset];
292
+ const power = {
293
+ // V2 uses state 3 in a live packet where the app treats it as normal battery.
294
+ state: this.protocol === "dms_v2" && rawState === 3 ? 0 : rawState,
295
+ percent: clamp(response[percentOffset], 0, 100),
296
+ profile: clamp(response[profileOffset], 0, ORBITAL_PROFILE_COUNT - 1),
297
+ };
298
+ if (this.settings)
299
+ this.settings.power = power;
300
+ return power;
301
+ }
302
+ // ---------------------------------------------------------------------------
303
+ // DPI / sensor / system settings
304
+ // ---------------------------------------------------------------------------
305
+ async readSettings() {
306
+ const settings = this.protocol === "dms_v2"
307
+ ? await this.readDmsV2Settings()
308
+ : await this.readDmsSettings();
309
+ this.settings = settings;
310
+ return settings;
311
+ }
312
+ /**
313
+ * Accepts a partial update. Missing values are copied from the current readback,
314
+ * which matters because the write packets contain fields the UI may not expose.
315
+ */
316
+ async applySettings(changes) {
317
+ const current = this.settings ?? await this.readSettings();
318
+ const merged = this.mergeEditableSettings(current, changes);
319
+ if (this.protocol === "dms_v2")
320
+ await this.writeDmsV2Settings(merged, current);
321
+ else
322
+ await this.writeDmsSettings(merged, current);
323
+ // Always read it back. A successful ACK only means the packet arrived; readback
324
+ // is what tells us the values really stuck.
325
+ return this.readSettings();
326
+ }
327
+ /**
328
+ * DMS v1 keeps DPI, rate, sensor flags, LOD, angle, sleep and debounce in one
329
+ * main settings response. The flag byte is decoded bit by bit below.
330
+ */
331
+ async readDmsSettings() {
332
+ const packet = this.packetWith([0, 4], [2, 129], [3, 1]);
333
+ const response = await this.requestResponse(packet, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 1, "read DMS settings");
334
+ const flags = response[4];
335
+ const dpiStages = Array.from({ length: 5 }, (_, stage) => {
336
+ const offset = 8 + stage * 4;
337
+ return [readU16LE(response, offset), readU16LE(response, offset + 2)];
338
+ });
339
+ const reportRateIndex = response[5] > 1 ? response[5] - 1 : 0;
340
+ const settings = {
341
+ protocol: "dms",
342
+ dpiStages,
343
+ dpiColors: Array.from({ length: 5 }, () => [0, 0, 0]),
344
+ enabledDpiStages: countSetBits(response[6]) || 5,
345
+ activeDpiStage: clamp(response[7], 0, 4),
346
+ reportRateIndex,
347
+ reportRateHz: ORBITAL_REPORT_RATES_HZ[reportRateIndex] ?? 0,
348
+ sleepSeconds: readU16LE(response, 52),
349
+ debounceMs: response[54],
350
+ sensor: {
351
+ angleSnapping: Boolean(flags & (1 << 0)),
352
+ maxSpeedMode: Boolean(flags & (1 << 1)),
353
+ rippleControl: Boolean(flags & (1 << 4)),
354
+ motionSync: Boolean(flags & (1 << 5)),
355
+ fullSpeedMode: Boolean(flags & (1 << 6)),
356
+ wheelReverse: Boolean(flags & (1 << 7)),
357
+ liftDownEnable: false,
358
+ glassMode: false,
359
+ liftOffDistance: response[43],
360
+ angleTuning: signedByte(response[44]),
361
+ },
362
+ };
363
+ // V1 puts wheel reverse in the sensor flags. Keep it in a normalized system
364
+ // object too, so a UI does not need separate code for V1 and V2.
365
+ settings.system = {
366
+ sleepSeconds: settings.sleepSeconds,
367
+ bleSleepSeconds: settings.sleepSeconds,
368
+ reportRateIndex,
369
+ debounceMs: settings.debounceMs,
370
+ quickResponse: false,
371
+ buttonWakeupEnable: false,
372
+ moveWakeupEnable: false,
373
+ wheelWakeupEnable: false,
374
+ wheelReverse: Boolean(flags & (1 << 7)),
375
+ irButtonMode: 0,
376
+ mouseLeftKeyMode: 0,
377
+ mouseRightKeyMode: 0,
378
+ rfPowerMode: 0,
379
+ bleNum: 0,
380
+ };
381
+ // Remove the temporary extra property from the normalized sensor object.
382
+ delete settings.sensor.wheelReverse;
383
+ return settings;
384
+ }
385
+ /**
386
+ * DMS v2 splits settings into two blocks:
387
+ *
388
+ * sensor/DPI read: [0]=0x04, [2]=0x81, [3]=0x01
389
+ * system read: [0]=0x04, [2]=0x83, [3]=0x03
390
+ *
391
+ * sensorData is response bytes after the four-byte command header.
392
+ * systemData is handled the same way.
393
+ */
394
+ async readDmsV2Settings() {
395
+ const sensorPacket = this.packetWith([0, 4], [2, 129], [3, 1]);
396
+ const sensorResponse = await this.requestResponse(sensorPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 1, "read DMS v2 sensor settings");
397
+ const systemPacket = this.packetWith([0, 4], [2, 131], [3, 3]);
398
+ const systemResponse = await this.requestResponse(systemPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 3, "read DMS v2 system settings");
399
+ const sensorData = sensorResponse.slice(4);
400
+ const systemData = systemResponse.slice(4);
401
+ const dpiStages = Array.from({ length: 5 }, (_, stage) => {
402
+ const offset = 11 + stage * 4;
403
+ return [readU16LE(sensorData, offset), readU16LE(sensorData, offset + 2)];
404
+ });
405
+ const dpiColors = Array.from({ length: 5 }, (_, stage) => {
406
+ const offset = 39 + stage * 3;
407
+ return [sensorData[offset], sensorData[offset + 1], sensorData[offset + 2]];
408
+ });
409
+ const system = {
410
+ sleepSeconds: readU16LE(systemData, 0),
411
+ bleSleepSeconds: readU16LE(systemData, 2),
412
+ reportRateIndex: systemData[4] > 1 ? systemData[4] - 1 : 0,
413
+ debounceMs: systemData[5],
414
+ quickResponse: Boolean(systemData[6]),
415
+ buttonWakeupEnable: Boolean(systemData[7]),
416
+ moveWakeupEnable: Boolean(systemData[8]),
417
+ wheelWakeupEnable: Boolean(systemData[9]),
418
+ wheelReverse: Boolean(systemData[10]),
419
+ irButtonMode: systemData[11],
420
+ mouseLeftKeyMode: systemData[12],
421
+ mouseRightKeyMode: systemData[13],
422
+ rfPowerMode: systemData[14],
423
+ bleNum: systemData[15],
424
+ };
425
+ return {
426
+ protocol: "dms_v2",
427
+ dpiStages,
428
+ dpiColors,
429
+ enabledDpiStages: countSetBits(sensorData[10]) || 5,
430
+ activeDpiStage: clamp(sensorData[9], 0, 4),
431
+ reportRateIndex: system.reportRateIndex,
432
+ reportRateHz: ORBITAL_REPORT_RATES_HZ[system.reportRateIndex] ?? 0,
433
+ sleepSeconds: system.sleepSeconds,
434
+ debounceMs: system.debounceMs,
435
+ sensor: {
436
+ angleSnapping: Boolean(sensorData[0]),
437
+ rippleControl: Boolean(sensorData[1]),
438
+ motionSync: Boolean(sensorData[2]),
439
+ fullSpeedMode: Boolean(sensorData[3]),
440
+ maxSpeedMode: Boolean(sensorData[4]),
441
+ liftDownEnable: Boolean(sensorData[5]),
442
+ glassMode: Boolean(sensorData[6]),
443
+ liftOffDistance: sensorData[7],
444
+ angleTuning: signedByte(sensorData[8]),
445
+ },
446
+ system,
447
+ };
448
+ }
449
+ /**
450
+ * Writes DMS v1 settings.
451
+ *
452
+ * V1 uses several commands instead of one clean settings block:
453
+ * 0xB5/0x02 main DPI + sensor packet
454
+ * 0x84/0x04 polling rate
455
+ * 0x84/0x0A LOD + angle
456
+ * 0x86/0x0E sleep + debounce
457
+ *
458
+ * Each write is saved before moving on. Existing fields are preserved where
459
+ * the packet contains values that this API does not edit.
460
+ */
461
+ async writeDmsSettings(next, previous) {
462
+ let flags = 0;
463
+ if (next.angleSnapping)
464
+ flags |= 1 << 0;
465
+ if (next.highPerformance)
466
+ flags |= 1 << 1;
467
+ if (next.rippleControl)
468
+ flags |= 1 << 4;
469
+ if (next.motionSync)
470
+ flags |= 1 << 5;
471
+ if (next.overclockedMode)
472
+ flags |= 1 << 6;
473
+ if (next.wheelReverse)
474
+ flags |= 1 << 7;
475
+ // Main V1 sensor/DPI packet.
476
+ const dpiPacket = this.makePacket();
477
+ dpiPacket[0] = 4;
478
+ dpiPacket[2] = 181;
479
+ dpiPacket[3] = 2;
480
+ dpiPacket[4] = flags;
481
+ dpiPacket[5] = encodeReportRate(next.reportRateIndex);
482
+ dpiPacket[6] = (1 << next.enabledDpiStages) - 1;
483
+ dpiPacket[7] = next.activeDpiStage;
484
+ next.dpiStages.forEach((pair, stage) => {
485
+ const offset = 8 + stage * 4;
486
+ writeU16LE(dpiPacket, offset, pair[0]);
487
+ writeU16LE(dpiPacket, offset + 2, pair[1]);
488
+ });
489
+ dpiPacket[43] = next.liftOffDistance;
490
+ dpiPacket[44] = next.angleTuning & 0xff;
491
+ // The packet contains old system fields too. Preserve them here and update them
492
+ // using the dedicated command below instead of accidentally zeroing them.
493
+ writeU16LE(dpiPacket, 50, previous.sleepSeconds);
494
+ writeU16LE(dpiPacket, 52, previous.sleepSeconds);
495
+ dpiPacket[54] = previous.debounceMs;
496
+ this.finishPacket(dpiPacket);
497
+ await this.requestResponse(dpiPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 2, "write V1 DPI/sensor settings");
498
+ await this.saveSettings();
499
+ const ratePacket = this.packetWith([0, 4], [2, 132], [3, 4], [4, encodeReportRate(next.reportRateIndex)]);
500
+ await this.requestResponse(ratePacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 4, "write V1 report rate");
501
+ await this.saveSettings();
502
+ const sensorPacket = this.packetWith([0, 4], [2, 132], [3, 10], [4, flags], [5, next.liftOffDistance], [6, next.angleTuning & 0xff]);
503
+ await this.requestResponse(sensorPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 10, "write V1 LOD/angle settings");
504
+ await this.saveSettings();
505
+ const systemPacket = this.packetWith([0, 4], [2, 134], [3, 14], [4, next.sleepSeconds & 0xff], [5, (next.sleepSeconds >>> 8) & 0xff], [6, next.sleepSeconds & 0xff], [7, (next.sleepSeconds >>> 8) & 0xff], [8, next.debounceMs]);
506
+ await this.requestResponse(systemPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 14, "write V1 debounce/sleep");
507
+ await this.saveSettings();
508
+ }
509
+ /**
510
+ * Writes DMS v2 settings.
511
+ *
512
+ * Sensor/DPI write packet:
513
+ * [0]=0x04 [2]=0xBC [3]=0x02
514
+ * [4..12] toggles, LOD and angle
515
+ * [13] active stage, [14] enabled-stage bit mask
516
+ * [15..34] five X/Y DPI pairs
517
+ * [43..57] existing stage colors, copied back unchanged
518
+ *
519
+ * System write packet:
520
+ * [0]=0x04 [2]=0x90 [3]=0x04
521
+ * sleep, report rate, debounce, quick response and wheel reverse
522
+ * plus pass-through bytes copied from the last read.
523
+ */
524
+ async writeDmsV2Settings(next, previous) {
525
+ const oldSensor = previous.sensor;
526
+ const sensorPacket = this.makePacket();
527
+ sensorPacket[0] = 4;
528
+ sensorPacket[2] = 188;
529
+ sensorPacket[3] = 2;
530
+ sensorPacket[4] = Number(next.angleSnapping);
531
+ sensorPacket[5] = Number(next.rippleControl);
532
+ sensorPacket[6] = Number(next.motionSync);
533
+ sensorPacket[7] = Number(next.overclockedMode);
534
+ sensorPacket[8] = Number(next.highPerformance);
535
+ sensorPacket[9] = Number(oldSensor.liftDownEnable);
536
+ sensorPacket[10] = Number(oldSensor.glassMode);
537
+ sensorPacket[11] = next.liftOffDistance;
538
+ sensorPacket[12] = next.angleTuning & 0xff;
539
+ sensorPacket[13] = next.activeDpiStage;
540
+ sensorPacket[14] = (1 << next.enabledDpiStages) - 1;
541
+ next.dpiStages.forEach((pair, stage) => {
542
+ const offset = 15 + stage * 4;
543
+ writeU16LE(sensorPacket, offset, pair[0]);
544
+ writeU16LE(sensorPacket, offset + 2, pair[1]);
545
+ });
546
+ previous.dpiColors.forEach((rgb, stage) => {
547
+ const offset = 43 + stage * 3;
548
+ sensorPacket[offset] = rgb[0] ?? 0;
549
+ sensorPacket[offset + 1] = rgb[1] ?? 0;
550
+ sensorPacket[offset + 2] = rgb[2] ?? 0;
551
+ });
552
+ this.finishPacket(sensorPacket);
553
+ await this.requestResponse(sensorPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 2, "write V2 sensor/DPI settings");
554
+ await this.saveSettings();
555
+ const oldSystem = previous.system;
556
+ if (!oldSystem)
557
+ throw new Error("V2 system settings were not read before writing.");
558
+ const systemPacket = this.makePacket();
559
+ systemPacket[0] = 4;
560
+ systemPacket[2] = 144;
561
+ systemPacket[3] = 4;
562
+ writeU16LE(systemPacket, 4, next.sleepSeconds);
563
+ writeU16LE(systemPacket, 6, next.sleepSeconds);
564
+ systemPacket[8] = encodeReportRate(next.reportRateIndex);
565
+ systemPacket[9] = next.debounceMs;
566
+ systemPacket[10] = Number(next.quickResponse);
567
+ systemPacket[11] = Number(oldSystem.buttonWakeupEnable);
568
+ systemPacket[12] = Number(oldSystem.moveWakeupEnable);
569
+ systemPacket[13] = Number(oldSystem.wheelWakeupEnable);
570
+ systemPacket[14] = Number(next.wheelReverse);
571
+ systemPacket[15] = oldSystem.irButtonMode;
572
+ systemPacket[16] = oldSystem.mouseLeftKeyMode;
573
+ systemPacket[17] = oldSystem.mouseRightKeyMode;
574
+ systemPacket[18] = oldSystem.rfPowerMode;
575
+ systemPacket[19] = oldSystem.bleNum;
576
+ this.finishPacket(systemPacket);
577
+ await this.requestResponse(systemPacket, (bytes) => (bytes[0] === 4 || bytes[0] === 68) && bytes[3] === 4, "write V2 system settings");
578
+ await this.saveSettings();
579
+ }
580
+ mergeEditableSettings(current, changes) {
581
+ const reportRateIndex = clamp(changes.reportRateIndex ?? current.reportRateIndex, 0, this.definition.maxReportRateIndex);
582
+ const dpiStages = normalizeDpiStages(changes.dpiStages ?? current.dpiStages);
583
+ const enabledDpiStages = clamp(changes.enabledDpiStages ?? current.enabledDpiStages, 1, 5);
584
+ return {
585
+ dpiStages,
586
+ enabledDpiStages,
587
+ activeDpiStage: clamp(changes.activeDpiStage ?? current.activeDpiStage, 0, enabledDpiStages - 1),
588
+ reportRateIndex,
589
+ sleepSeconds: clamp(changes.sleepSeconds ?? current.sleepSeconds, 1, 0xffff),
590
+ debounceMs: clamp(changes.debounceMs ?? current.debounceMs, 0, 30),
591
+ liftOffDistance: clamp(changes.liftOffDistance ?? current.sensor.liftOffDistance, 0, 2),
592
+ angleTuning: clamp(changes.angleTuning ?? current.sensor.angleTuning, -30, 30),
593
+ angleSnapping: changes.angleSnapping ?? current.sensor.angleSnapping,
594
+ rippleControl: changes.rippleControl ?? current.sensor.rippleControl,
595
+ motionSync: changes.motionSync ?? current.sensor.motionSync,
596
+ highPerformance: changes.highPerformance ?? current.sensor.maxSpeedMode,
597
+ overclockedMode: changes.overclockedMode ?? current.sensor.fullSpeedMode,
598
+ quickResponse: changes.quickResponse ?? current.system?.quickResponse ?? false,
599
+ wheelReverse: changes.wheelReverse ?? current.system?.wheelReverse ?? false,
600
+ };
601
+ }
602
+ // ---------------------------------------------------------------------------
603
+ // Onboard profiles
604
+ // ---------------------------------------------------------------------------
605
+ /**
606
+ * Switches the active onboard profile. Profiles are zero-based here, so 0 is
607
+ * the mouse's Profile 1. The ACK can arrive before the switch is complete;
608
+ * readPower() is used to verify the profile really changed.
609
+ */
610
+ async switchProfile(profile) {
611
+ const target = clamp(profile, 0, ORBITAL_PROFILE_COUNT - 1);
612
+ const command = this.protocol === "dms_v2" ? 2 : 1;
613
+ let lastError;
614
+ // The device sometimes ACKs before it has actually switched profile, so verify
615
+ // using the battery/status packet instead of trusting the ACK on its own.
616
+ for (let attempt = 1; attempt <= 3; attempt += 1) {
617
+ try {
618
+ const packet = this.packetWith([0, 2], [2, 130], [3, command], [4, target]);
619
+ await this.requestResponse(packet, (bytes) => (bytes[0] === 2 || bytes[0] === 66) && bytes[3] === command, `switch profile to ${target + 1}`, 2800);
620
+ await this.saveSettings(2800);
621
+ }
622
+ catch (error) {
623
+ lastError = error;
624
+ }
625
+ await delay(140 + attempt * 80);
626
+ try {
627
+ const power = await this.readPower();
628
+ if (power.profile === target)
629
+ return power;
630
+ }
631
+ catch (error) {
632
+ lastError = error;
633
+ }
634
+ }
635
+ throw new Error(`Profile ${target + 1} did not activate. ${errorMessage(lastError)}`.trim());
636
+ }
637
+ // ---------------------------------------------------------------------------
638
+ // Factory reset and low-level helper
639
+ // ---------------------------------------------------------------------------
640
+ async factoryReset() {
641
+ const packet = this.protocol === "dms_v2"
642
+ ? this.packetWith([0, 9], [2, 129], [3, 255], [4, 0])
643
+ : this.packetWith([0, 9], [2, 130], [3, 0], [4, 255]);
644
+ // Factory reset does not always send a useful ACK, so the original app sends it,
645
+ // waits, saves, waits again, then verifies by reading the settings back.
646
+ await this.sendPacket(packet, "factory reset");
647
+ await delay(250);
648
+ await this.saveSettings();
649
+ await delay(250);
650
+ return this.readSettings();
651
+ }
652
+ /**
653
+ * Useful while OpenMouse is still wiring things up. The packet must already be
654
+ * 64 bytes; this method handles receiver routing and checksum.
655
+ */
656
+ async rawCommand(packet, predicate, label = "raw Orbital command", timeoutMs = this.timeoutMs, routeToMouse = true) {
657
+ if (packet.length !== ORBITAL_PACKET_SIZE) {
658
+ throw new Error(`Orbital packets must be ${ORBITAL_PACKET_SIZE} bytes.`);
659
+ }
660
+ const copy = packet.slice();
661
+ this.finishPacket(copy, routeToMouse);
662
+ return this.requestResponse(copy, predicate, label, timeoutMs);
663
+ }
664
+ // ---------------------------------------------------------------------------
665
+ // Transport internals
666
+ // ---------------------------------------------------------------------------
667
+ handleInputReport(event) {
668
+ const view = event.data;
669
+ const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength).slice();
670
+ const reportId = Number(event.reportId ?? 0);
671
+ this.logger(`IN report 0x${reportId.toString(16).padStart(2, "0")}`, bytes);
672
+ this.handleLiveStatus(bytes);
673
+ for (const waiter of Array.from(this.waiters)) {
674
+ if (!waiter.predicate(bytes, reportId))
675
+ continue;
676
+ this.waiters.delete(waiter);
677
+ clearTimeout(waiter.timer);
678
+ waiter.resolve(bytes);
679
+ }
680
+ }
681
+ handleDisconnect() {
682
+ this.rejectAllWaiters(new Error("Orbital device disconnected."));
683
+ }
684
+ handleLiveStatus(bytes) {
685
+ if (bytes[3] !== 1)
686
+ return;
687
+ let rawState;
688
+ let percent;
689
+ let profile;
690
+ let activeDpiStage;
691
+ let reportRateIndex;
692
+ if (this.protocol === "dms" &&
693
+ (bytes[0] === 1 || bytes[0] === 65) &&
694
+ bytes[2] === 142) {
695
+ rawState = bytes[5];
696
+ percent = bytes[6];
697
+ profile = bytes[7];
698
+ activeDpiStage = bytes[8];
699
+ reportRateIndex = bytes[9] > 0 ? bytes[9] - 1 : bytes[9];
700
+ }
701
+ else if (this.protocol === "dms_v2" &&
702
+ (bytes[0] === 1 || bytes[0] === 65) &&
703
+ (bytes[2] === 152 || bytes[2] === 153)) {
704
+ rawState = bytes[10];
705
+ percent = bytes[11];
706
+ profile = bytes[12];
707
+ activeDpiStage = bytes[13];
708
+ reportRateIndex = bytes[20] > 0 ? bytes[20] - 1 : bytes[20];
709
+ }
710
+ if (rawState === undefined || percent === undefined || profile === undefined)
711
+ return;
712
+ const power = {
713
+ state: this.protocol === "dms_v2" && rawState === 3 ? 0 : rawState,
714
+ percent: clamp(percent, 0, 100),
715
+ profile: clamp(profile, 0, ORBITAL_PROFILE_COUNT - 1),
716
+ };
717
+ if (this.settings) {
718
+ this.settings.power = power;
719
+ if (activeDpiStage !== undefined && activeDpiStage >= 0 && activeDpiStage < 5) {
720
+ this.settings.activeDpiStage = activeDpiStage;
721
+ }
722
+ if (reportRateIndex !== undefined &&
723
+ reportRateIndex >= 0 &&
724
+ reportRateIndex < ORBITAL_REPORT_RATES_HZ.length) {
725
+ this.settings.reportRateIndex = reportRateIndex;
726
+ this.settings.reportRateHz = ORBITAL_REPORT_RATES_HZ[reportRateIndex];
727
+ }
728
+ }
729
+ const update = { power, activeDpiStage, reportRateIndex };
730
+ for (const listener of this.updateListeners)
731
+ listener(update);
732
+ }
733
+ makePacket() {
734
+ return new Uint8Array(ORBITAL_PACKET_SIZE);
735
+ }
736
+ packetWith(...pairs) {
737
+ const packet = this.makePacket();
738
+ for (const [offset, value] of pairs)
739
+ packet[offset] = value;
740
+ return this.finishPacket(packet);
741
+ }
742
+ /**
743
+ * Applies receiver routing and the checksum in the required order.
744
+ * Do not calculate the checksum first and set 0x40 afterward; that produces a
745
+ * packet the receiver will reject.
746
+ */
747
+ finishPacket(packet, routeToMouse = true) {
748
+ packet.set(orbitalFinishPacket(packet, this.isReceiver && routeToMouse));
749
+ return packet;
750
+ }
751
+ async sendPacket(packet, label) {
752
+ if (!this.device.opened)
753
+ throw new Error("Orbital device is not open.");
754
+ this.logger(`OUT report 0x${ORBITAL_REPORT_ID.toString(16).padStart(2, "0")} - ${label}`, packet);
755
+ await this.device.sendReport(ORBITAL_REPORT_ID, packet);
756
+ }
757
+ async requestResponse(packet, predicate, label, timeoutMs = this.timeoutMs) {
758
+ // Register the waiter first. Some devices answer quickly enough that doing this
759
+ // after sendReport creates a tiny race and misses the reply.
760
+ const response = this.waitForReport(predicate, timeoutMs);
761
+ await this.sendPacket(packet, label);
762
+ return response;
763
+ }
764
+ waitForReport(predicate, timeoutMs) {
765
+ return new Promise((resolve, reject) => {
766
+ const waiter = {
767
+ predicate,
768
+ resolve,
769
+ reject,
770
+ timer: setTimeout(() => {
771
+ this.waiters.delete(waiter);
772
+ reject(new Error("Timed out waiting for the Orbital response."));
773
+ }, timeoutMs),
774
+ };
775
+ this.waiters.add(waiter);
776
+ });
777
+ }
778
+ async saveSettings(timeoutMs = this.timeoutMs) {
779
+ const packet = this.packetWith([0, 10], [2, 129], [3, 1]);
780
+ await this.requestResponse(packet, (bytes) => bytes[0] === 10 || bytes[0] === 74, "save settings", timeoutMs);
781
+ }
782
+ rejectAllWaiters(error) {
783
+ for (const waiter of this.waiters) {
784
+ clearTimeout(waiter.timer);
785
+ waiter.reject(error);
786
+ }
787
+ this.waiters.clear();
788
+ }
789
+ }
790
+ // -----------------------------------------------------------------------------
791
+ // Helpers kept outside the class so they are easy to reuse in another transport
792
+ // -----------------------------------------------------------------------------
793
+ function hasOrbitalConfigCollection(device) {
794
+ return Boolean(device.collections?.some((collection) => collection.usage === 1 && collection.usagePage === 0xff0a));
795
+ }
796
+ function reportRateIndexToHz(index) {
797
+ return ORBITAL_REPORT_RATES_HZ[clamp(index, 0, ORBITAL_REPORT_RATES_HZ.length - 1)];
798
+ }
799
+ function reportRateHzToIndex(hz) {
800
+ const exact = ORBITAL_REPORT_RATES_HZ.indexOf(hz);
801
+ if (exact >= 0)
802
+ return exact;
803
+ // Handy for a generic UI: pick the closest supported rate instead of throwing.
804
+ return ORBITAL_REPORT_RATES_HZ.reduce((best, rate, index) => Math.abs(rate - hz) < Math.abs(ORBITAL_REPORT_RATES_HZ[best] - hz) ? index : best, 0);
805
+ }
806
+ function powerStateLabel(power) {
807
+ if (power.state === 2)
808
+ return "fully charged";
809
+ if (power.state === 1 || power.state === 3)
810
+ return "charging";
811
+ return "on battery";
812
+ }
813
+ function normalizeDpiStages(input) {
814
+ const fallback = [
815
+ [400, 400],
816
+ [800, 800],
817
+ [1600, 1600],
818
+ [3200, 3200],
819
+ [4800, 4800],
820
+ ];
821
+ return Array.from({ length: 5 }, (_, index) => {
822
+ const pair = input[index] ?? fallback[index];
823
+ return [normalizeDpi(pair[0]), normalizeDpi(pair[1])];
824
+ });
825
+ }
826
+ function normalizeDpi(value) {
827
+ const stepped = Math.round(Number(value) / ORBITAL_DPI_LIMITS.step) * ORBITAL_DPI_LIMITS.step;
828
+ return clamp(stepped, ORBITAL_DPI_LIMITS.min, ORBITAL_DPI_LIMITS.max);
829
+ }
830
+ function encodeReportRate(index) {
831
+ return index > 0 ? index + 1 : 0;
832
+ }
833
+ function signedByte(value) {
834
+ return value <= 30 ? value : value - 256;
835
+ }
836
+ function countSetBits(value) {
837
+ let count = 0;
838
+ for (let byte = value; byte; byte >>>= 1)
839
+ count += byte & 1;
840
+ return count;
841
+ }
842
+ function readU16LE(bytes, offset) {
843
+ return bytes[offset] | (bytes[offset + 1] << 8);
844
+ }
845
+ function writeU16LE(bytes, offset, value) {
846
+ bytes[offset] = value & 0xff;
847
+ bytes[offset + 1] = (value >>> 8) & 0xff;
848
+ }
849
+ function clamp(value, minimum, maximum) {
850
+ return Math.min(maximum, Math.max(minimum, Number(value)));
851
+ }
852
+ function delay(milliseconds) {
853
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
854
+ }
855
+ function toHex4(value) {
856
+ return value.toString(16).padStart(4, "0").toUpperCase();
857
+ }
858
+ function errorMessage(error) {
859
+ return error instanceof Error ? error.message : String(error ?? "");
860
+ }
861
+ // One object works in Electron/CommonJS and as a normal browser script.
862
+ const OrbitalHostProtocol = Object.freeze({
863
+ ORBITAL_VENDOR_ID,
864
+ ORBITAL_REPORT_ID,
865
+ ORBITAL_PACKET_SIZE,
866
+ ORBITAL_PROFILE_COUNT,
867
+ ORBITAL_DPI_LIMITS,
868
+ ORBITAL_REPORT_RATES_HZ,
869
+ ORBITAL_DEVICES,
870
+ OrbitalMouseClient,
871
+ hasOrbitalConfigCollection,
872
+ reportRateIndexToHz,
873
+ reportRateHzToIndex,
874
+ powerStateLabel,
875
+ normalizeDpiStages,
876
+ normalizeDpi,
877
+ });
878
+ if (typeof module !== "undefined" && module.exports) {
879
+ module.exports = OrbitalHostProtocol;
880
+ }
881
+ if (typeof globalThis !== "undefined") {
882
+ globalThis.OrbitalHostProtocol = OrbitalHostProtocol;
883
+ }
884
+ //# sourceMappingURL=host-protocol.js.map