@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.
- package/CONTRIBUTING.md +167 -0
- package/README.md +89 -0
- package/dist/asus/index.d.ts +52 -0
- package/dist/asus/index.d.ts.map +1 -0
- package/dist/asus/index.js +248 -0
- package/dist/asus/index.js.map +1 -0
- package/dist/atk/index.d.ts +200 -0
- package/dist/atk/index.d.ts.map +1 -0
- package/dist/atk/index.js +480 -0
- package/dist/atk/index.js.map +1 -0
- package/dist/bitmouse/index.d.ts +284 -0
- package/dist/bitmouse/index.d.ts.map +1 -0
- package/dist/bitmouse/index.js +396 -0
- package/dist/bitmouse/index.js.map +1 -0
- package/dist/compx/codec.d.ts +31 -0
- package/dist/compx/codec.d.ts.map +1 -0
- package/dist/compx/codec.js +50 -0
- package/dist/compx/codec.js.map +1 -0
- package/dist/corsair/index.d.ts +147 -0
- package/dist/corsair/index.d.ts.map +1 -0
- package/dist/corsair/index.js +223 -0
- package/dist/corsair/index.js.map +1 -0
- package/dist/dareu/index.d.ts +136 -0
- package/dist/dareu/index.d.ts.map +1 -0
- package/dist/dareu/index.js +344 -0
- package/dist/dareu/index.js.map +1 -0
- package/dist/drivers/asus/hid.d.ts +29 -0
- package/dist/drivers/asus/hid.d.ts.map +1 -0
- package/dist/drivers/asus/hid.js +419 -0
- package/dist/drivers/asus/hid.js.map +1 -0
- package/dist/drivers/atk/bitmouse-hid.d.ts +80 -0
- package/dist/drivers/atk/bitmouse-hid.d.ts.map +1 -0
- package/dist/drivers/atk/bitmouse-hid.js +501 -0
- package/dist/drivers/atk/bitmouse-hid.js.map +1 -0
- package/dist/drivers/atk/hid.d.ts +163 -0
- package/dist/drivers/atk/hid.d.ts.map +1 -0
- package/dist/drivers/atk/hid.js +1368 -0
- package/dist/drivers/atk/hid.js.map +1 -0
- package/dist/drivers/atk/products.d.ts +13 -0
- package/dist/drivers/atk/products.d.ts.map +1 -0
- package/dist/drivers/atk/products.js +13 -0
- package/dist/drivers/atk/products.js.map +1 -0
- package/dist/drivers/attackshark/dpi.d.ts +41 -0
- package/dist/drivers/attackshark/dpi.d.ts.map +1 -0
- package/dist/drivers/attackshark/dpi.js +215 -0
- package/dist/drivers/attackshark/dpi.js.map +1 -0
- package/dist/drivers/attackshark/hid.d.ts +124 -0
- package/dist/drivers/attackshark/hid.d.ts.map +1 -0
- package/dist/drivers/attackshark/hid.js +728 -0
- package/dist/drivers/attackshark/hid.js.map +1 -0
- package/dist/drivers/corsair/hid.d.ts +70 -0
- package/dist/drivers/corsair/hid.d.ts.map +1 -0
- package/dist/drivers/corsair/hid.js +414 -0
- package/dist/drivers/corsair/hid.js.map +1 -0
- package/dist/drivers/dareu/hid.d.ts +59 -0
- package/dist/drivers/dareu/hid.d.ts.map +1 -0
- package/dist/drivers/dareu/hid.js +478 -0
- package/dist/drivers/dareu/hid.js.map +1 -0
- package/dist/drivers/endgame/egg-op1-hid.d.ts +107 -0
- package/dist/drivers/endgame/egg-op1-hid.d.ts.map +1 -0
- package/dist/drivers/endgame/egg-op1-hid.js +605 -0
- package/dist/drivers/endgame/egg-op1-hid.js.map +1 -0
- package/dist/drivers/endgame/egg-we-control.d.ts +42 -0
- package/dist/drivers/endgame/egg-we-control.d.ts.map +1 -0
- package/dist/drivers/endgame/egg-we-control.js +87 -0
- package/dist/drivers/endgame/egg-we-control.js.map +1 -0
- package/dist/drivers/endgame/egg-we-hid.d.ts +58 -0
- package/dist/drivers/endgame/egg-we-hid.d.ts.map +1 -0
- package/dist/drivers/endgame/egg-we-hid.js +514 -0
- package/dist/drivers/endgame/egg-we-hid.js.map +1 -0
- package/dist/drivers/fantech/hid.d.ts +106 -0
- package/dist/drivers/fantech/hid.d.ts.map +1 -0
- package/dist/drivers/fantech/hid.js +295 -0
- package/dist/drivers/fantech/hid.js.map +1 -0
- package/dist/drivers/finalmouse/hid.d.ts +31 -0
- package/dist/drivers/finalmouse/hid.d.ts.map +1 -0
- package/dist/drivers/finalmouse/hid.js +181 -0
- package/dist/drivers/finalmouse/hid.js.map +1 -0
- package/dist/drivers/gearhub/hid.d.ts +191 -0
- package/dist/drivers/gearhub/hid.d.ts.map +1 -0
- package/dist/drivers/gearhub/hid.js +542 -0
- package/dist/drivers/gearhub/hid.js.map +1 -0
- package/dist/drivers/glorious/classic-hid.d.ts +62 -0
- package/dist/drivers/glorious/classic-hid.d.ts.map +1 -0
- package/dist/drivers/glorious/classic-hid.js +326 -0
- package/dist/drivers/glorious/classic-hid.js.map +1 -0
- package/dist/drivers/glorious/hid.d.ts +39 -0
- package/dist/drivers/glorious/hid.d.ts.map +1 -0
- package/dist/drivers/glorious/hid.js +203 -0
- package/dist/drivers/glorious/hid.js.map +1 -0
- package/dist/drivers/gwolves/hid.d.ts +27 -0
- package/dist/drivers/gwolves/hid.d.ts.map +1 -0
- package/dist/drivers/gwolves/hid.js +225 -0
- package/dist/drivers/gwolves/hid.js.map +1 -0
- package/dist/drivers/gwolves/products.d.ts +17 -0
- package/dist/drivers/gwolves/products.d.ts.map +1 -0
- package/dist/drivers/gwolves/products.js +58 -0
- package/dist/drivers/gwolves/products.js.map +1 -0
- package/dist/drivers/hyperx/hid.d.ts +59 -0
- package/dist/drivers/hyperx/hid.d.ts.map +1 -0
- package/dist/drivers/hyperx/hid.js +229 -0
- package/dist/drivers/hyperx/hid.js.map +1 -0
- package/dist/drivers/incott/hid.d.ts +513 -0
- package/dist/drivers/incott/hid.d.ts.map +1 -0
- package/dist/drivers/incott/hid.js +1173 -0
- package/dist/drivers/incott/hid.js.map +1 -0
- package/dist/drivers/index.d.ts +5 -0
- package/dist/drivers/index.d.ts.map +1 -0
- package/dist/drivers/index.js +5 -0
- package/dist/drivers/index.js.map +1 -0
- package/dist/drivers/keychron/m6-hid.d.ts +81 -0
- package/dist/drivers/keychron/m6-hid.d.ts.map +1 -0
- package/dist/drivers/keychron/m6-hid.js +486 -0
- package/dist/drivers/keychron/m6-hid.js.map +1 -0
- package/dist/drivers/keychron/nape-hid.d.ts +60 -0
- package/dist/drivers/keychron/nape-hid.d.ts.map +1 -0
- package/dist/drivers/keychron/nape-hid.js +432 -0
- package/dist/drivers/keychron/nape-hid.js.map +1 -0
- package/dist/drivers/ksnake/hid.d.ts +74 -0
- package/dist/drivers/ksnake/hid.d.ts.map +1 -0
- package/dist/drivers/ksnake/hid.js +368 -0
- package/dist/drivers/ksnake/hid.js.map +1 -0
- package/dist/drivers/lamzu/hid.d.ts +58 -0
- package/dist/drivers/lamzu/hid.d.ts.map +1 -0
- package/dist/drivers/lamzu/hid.js +414 -0
- package/dist/drivers/lamzu/hid.js.map +1 -0
- package/dist/drivers/lamzu-atlantis/hid.d.ts +148 -0
- package/dist/drivers/lamzu-atlantis/hid.d.ts.map +1 -0
- package/dist/drivers/lamzu-atlantis/hid.js +587 -0
- package/dist/drivers/lamzu-atlantis/hid.js.map +1 -0
- package/dist/drivers/logitech/bolt.d.ts +41 -0
- package/dist/drivers/logitech/bolt.d.ts.map +1 -0
- package/dist/drivers/logitech/bolt.js +105 -0
- package/dist/drivers/logitech/bolt.js.map +1 -0
- package/dist/drivers/logitech/hidpp.d.ts +525 -0
- package/dist/drivers/logitech/hidpp.d.ts.map +1 -0
- package/dist/drivers/logitech/hidpp.js +2774 -0
- package/dist/drivers/logitech/hidpp.js.map +1 -0
- package/dist/drivers/logitech/mode-status.d.ts +53 -0
- package/dist/drivers/logitech/mode-status.d.ts.map +1 -0
- package/dist/drivers/logitech/mode-status.js +52 -0
- package/dist/drivers/logitech/mode-status.js.map +1 -0
- package/dist/drivers/logitech/onboard-profiles.d.ts +298 -0
- package/dist/drivers/logitech/onboard-profiles.d.ts.map +1 -0
- package/dist/drivers/logitech/onboard-profiles.js +965 -0
- package/dist/drivers/logitech/onboard-profiles.js.map +1 -0
- package/dist/drivers/logitech/rgb-effects.d.ts +20 -0
- package/dist/drivers/logitech/rgb-effects.d.ts.map +1 -0
- package/dist/drivers/logitech/rgb-effects.js +93 -0
- package/dist/drivers/logitech/rgb-effects.js.map +1 -0
- package/dist/drivers/mchose/a5-gen1-hid.d.ts +36 -0
- package/dist/drivers/mchose/a5-gen1-hid.d.ts.map +1 -0
- package/dist/drivers/mchose/a5-gen1-hid.js +219 -0
- package/dist/drivers/mchose/a5-gen1-hid.js.map +1 -0
- package/dist/drivers/mchose/dock-hid.d.ts +26 -0
- package/dist/drivers/mchose/dock-hid.d.ts.map +1 -0
- package/dist/drivers/mchose/dock-hid.js +176 -0
- package/dist/drivers/mchose/dock-hid.js.map +1 -0
- package/dist/drivers/mchose/hid.d.ts +118 -0
- package/dist/drivers/mchose/hid.d.ts.map +1 -0
- package/dist/drivers/mchose/hid.js +550 -0
- package/dist/drivers/mchose/hid.js.map +1 -0
- package/dist/drivers/mchose/v3-hid.d.ts +109 -0
- package/dist/drivers/mchose/v3-hid.d.ts.map +1 -0
- package/dist/drivers/mchose/v3-hid.js +572 -0
- package/dist/drivers/mchose/v3-hid.js.map +1 -0
- package/dist/drivers/microsoft/hid.d.ts +25 -0
- package/dist/drivers/microsoft/hid.d.ts.map +1 -0
- package/dist/drivers/microsoft/hid.js +247 -0
- package/dist/drivers/microsoft/hid.js.map +1 -0
- package/dist/drivers/moddo/hid.d.ts +31 -0
- package/dist/drivers/moddo/hid.d.ts.map +1 -0
- package/dist/drivers/moddo/hid.js +154 -0
- package/dist/drivers/moddo/hid.js.map +1 -0
- package/dist/drivers/mouse-types.d.ts +388 -0
- package/dist/drivers/mouse-types.d.ts.map +1 -0
- package/dist/drivers/mouse-types.js +2 -0
- package/dist/drivers/mouse-types.js.map +1 -0
- package/dist/drivers/ninjutso/hid.d.ts +62 -0
- package/dist/drivers/ninjutso/hid.d.ts.map +1 -0
- package/dist/drivers/ninjutso/hid.js +680 -0
- package/dist/drivers/ninjutso/hid.js.map +1 -0
- package/dist/drivers/orbital/hid.d.ts +24 -0
- package/dist/drivers/orbital/hid.d.ts.map +1 -0
- package/dist/drivers/orbital/hid.js +85 -0
- package/dist/drivers/orbital/hid.js.map +1 -0
- package/dist/drivers/orbital/host-protocol.d.ts +59 -0
- package/dist/drivers/orbital/host-protocol.d.ts.map +1 -0
- package/dist/drivers/orbital/host-protocol.js +884 -0
- package/dist/drivers/orbital/host-protocol.js.map +1 -0
- package/dist/drivers/pulsar/pulsar-hid.d.ts +63 -0
- package/dist/drivers/pulsar/pulsar-hid.d.ts.map +1 -0
- package/dist/drivers/pulsar/pulsar-hid.js +381 -0
- package/dist/drivers/pulsar/pulsar-hid.js.map +1 -0
- package/dist/drivers/pulsar/pulsar-pro-hid.d.ts +46 -0
- package/dist/drivers/pulsar/pulsar-pro-hid.d.ts.map +1 -0
- package/dist/drivers/pulsar/pulsar-pro-hid.js +343 -0
- package/dist/drivers/pulsar/pulsar-pro-hid.js.map +1 -0
- package/dist/drivers/pulsar/pulsar-xs1-hid.d.ts +40 -0
- package/dist/drivers/pulsar/pulsar-xs1-hid.d.ts.map +1 -0
- package/dist/drivers/pulsar/pulsar-xs1-hid.js +251 -0
- package/dist/drivers/pulsar/pulsar-xs1-hid.js.map +1 -0
- package/dist/drivers/rawm/hid.d.ts +29 -0
- package/dist/drivers/rawm/hid.d.ts.map +1 -0
- package/dist/drivers/rawm/hid.js +210 -0
- package/dist/drivers/rawm/hid.js.map +1 -0
- package/dist/drivers/razer/cobra-hid.d.ts +63 -0
- package/dist/drivers/razer/cobra-hid.d.ts.map +1 -0
- package/dist/drivers/razer/cobra-hid.js +282 -0
- package/dist/drivers/razer/cobra-hid.js.map +1 -0
- package/dist/drivers/razer/hid-open.d.ts +13 -0
- package/dist/drivers/razer/hid-open.d.ts.map +1 -0
- package/dist/drivers/razer/hid-open.js +29 -0
- package/dist/drivers/razer/hid-open.js.map +1 -0
- package/dist/drivers/razer/hid.d.ts +231 -0
- package/dist/drivers/razer/hid.d.ts.map +1 -0
- package/dist/drivers/razer/hid.js +772 -0
- package/dist/drivers/razer/hid.js.map +1 -0
- package/dist/drivers/razer/viper-hid.d.ts +33 -0
- package/dist/drivers/razer/viper-hid.d.ts.map +1 -0
- package/dist/drivers/razer/viper-hid.js +177 -0
- package/dist/drivers/razer/viper-hid.js.map +1 -0
- package/dist/drivers/razer/viper-mini-hid.d.ts +58 -0
- package/dist/drivers/razer/viper-mini-hid.d.ts.map +1 -0
- package/dist/drivers/razer/viper-mini-hid.js +273 -0
- package/dist/drivers/razer/viper-mini-hid.js.map +1 -0
- package/dist/drivers/razer/viper-v4-pro-hid.d.ts +26 -0
- package/dist/drivers/razer/viper-v4-pro-hid.d.ts.map +1 -0
- package/dist/drivers/razer/viper-v4-pro-hid.js +154 -0
- package/dist/drivers/razer/viper-v4-pro-hid.js.map +1 -0
- package/dist/drivers/registry.d.ts +70 -0
- package/dist/drivers/registry.d.ts.map +1 -0
- package/dist/drivers/registry.js +146 -0
- package/dist/drivers/registry.js.map +1 -0
- package/dist/drivers/steelseries/aerox3-hid.d.ts +53 -0
- package/dist/drivers/steelseries/aerox3-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/aerox3-hid.js +172 -0
- package/dist/drivers/steelseries/aerox3-hid.js.map +1 -0
- package/dist/drivers/steelseries/aerox5-hid.d.ts +54 -0
- package/dist/drivers/steelseries/aerox5-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/aerox5-hid.js +173 -0
- package/dist/drivers/steelseries/aerox5-hid.js.map +1 -0
- package/dist/drivers/steelseries/aerox5-wireless-hid.d.ts +69 -0
- package/dist/drivers/steelseries/aerox5-wireless-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/aerox5-wireless-hid.js +234 -0
- package/dist/drivers/steelseries/aerox5-wireless-hid.js.map +1 -0
- package/dist/drivers/steelseries/aerox9-wireless-hid.d.ts +70 -0
- package/dist/drivers/steelseries/aerox9-wireless-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/aerox9-wireless-hid.js +227 -0
- package/dist/drivers/steelseries/aerox9-wireless-hid.js.map +1 -0
- package/dist/drivers/steelseries/hid.d.ts +48 -0
- package/dist/drivers/steelseries/hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/hid.js +157 -0
- package/dist/drivers/steelseries/hid.js.map +1 -0
- package/dist/drivers/steelseries/prime-mini-wireless-hid.d.ts +62 -0
- package/dist/drivers/steelseries/prime-mini-wireless-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/prime-mini-wireless-hid.js +215 -0
- package/dist/drivers/steelseries/prime-mini-wireless-hid.js.map +1 -0
- package/dist/drivers/steelseries/prime-plus-hid.d.ts +51 -0
- package/dist/drivers/steelseries/prime-plus-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/prime-plus-hid.js +150 -0
- package/dist/drivers/steelseries/prime-plus-hid.js.map +1 -0
- package/dist/drivers/steelseries/rival3-wireless-hid.d.ts +61 -0
- package/dist/drivers/steelseries/rival3-wireless-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/rival3-wireless-hid.js +185 -0
- package/dist/drivers/steelseries/rival3-wireless-hid.js.map +1 -0
- package/dist/drivers/steelseries/rival310-hid.d.ts +59 -0
- package/dist/drivers/steelseries/rival310-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/rival310-hid.js +182 -0
- package/dist/drivers/steelseries/rival310-hid.js.map +1 -0
- package/dist/drivers/steelseries/rival650-hid.d.ts +68 -0
- package/dist/drivers/steelseries/rival650-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/rival650-hid.js +209 -0
- package/dist/drivers/steelseries/rival650-hid.js.map +1 -0
- package/dist/drivers/steelseries/sensei-ten-hid.d.ts +62 -0
- package/dist/drivers/steelseries/sensei-ten-hid.d.ts.map +1 -0
- package/dist/drivers/steelseries/sensei-ten-hid.js +186 -0
- package/dist/drivers/steelseries/sensei-ten-hid.js.map +1 -0
- package/dist/drivers/teevolution/hid.d.ts +82 -0
- package/dist/drivers/teevolution/hid.d.ts.map +1 -0
- package/dist/drivers/teevolution/hid.js +607 -0
- package/dist/drivers/teevolution/hid.js.map +1 -0
- package/dist/drivers/vendors.d.ts +254 -0
- package/dist/drivers/vendors.d.ts.map +1 -0
- package/dist/drivers/vendors.js +587 -0
- package/dist/drivers/vendors.js.map +1 -0
- package/dist/drivers/vgn/hid.d.ts +33 -0
- package/dist/drivers/vgn/hid.d.ts.map +1 -0
- package/dist/drivers/vgn/hid.js +213 -0
- package/dist/drivers/vgn/hid.js.map +1 -0
- package/dist/drivers/wallhack/keyboard-hid.d.ts +28 -0
- package/dist/drivers/wallhack/keyboard-hid.d.ts.map +1 -0
- package/dist/drivers/wallhack/keyboard-hid.js +80 -0
- package/dist/drivers/wallhack/keyboard-hid.js.map +1 -0
- package/dist/drivers/wallhack/mouse-hid.d.ts +45 -0
- package/dist/drivers/wallhack/mouse-hid.d.ts.map +1 -0
- package/dist/drivers/wallhack/mouse-hid.js +288 -0
- package/dist/drivers/wallhack/mouse-hid.js.map +1 -0
- package/dist/drivers/webhid.d.ts +59 -0
- package/dist/drivers/webhid.d.ts.map +1 -0
- package/dist/drivers/webhid.js +2 -0
- package/dist/drivers/webhid.js.map +1 -0
- package/dist/drivers/wlmouse/hid.d.ts +81 -0
- package/dist/drivers/wlmouse/hid.d.ts.map +1 -0
- package/dist/drivers/wlmouse/hid.js +576 -0
- package/dist/drivers/wlmouse/hid.js.map +1 -0
- package/dist/drivers/wooting/hid.d.ts +86 -0
- package/dist/drivers/wooting/hid.d.ts.map +1 -0
- package/dist/drivers/wooting/hid.js +320 -0
- package/dist/drivers/wooting/hid.js.map +1 -0
- package/dist/drivers/zaunkoenig/hid.d.ts +31 -0
- package/dist/drivers/zaunkoenig/hid.d.ts.map +1 -0
- package/dist/drivers/zaunkoenig/hid.js +162 -0
- package/dist/drivers/zaunkoenig/hid.js.map +1 -0
- package/dist/endgame-gear/op1.d.ts +165 -0
- package/dist/endgame-gear/op1.d.ts.map +1 -0
- package/dist/endgame-gear/op1.js +384 -0
- package/dist/endgame-gear/op1.js.map +1 -0
- package/dist/endgame-gear/wireless.d.ts +93 -0
- package/dist/endgame-gear/wireless.d.ts.map +1 -0
- package/dist/endgame-gear/wireless.js +242 -0
- package/dist/endgame-gear/wireless.js.map +1 -0
- package/dist/fantech/index.d.ts +9 -0
- package/dist/fantech/index.d.ts.map +1 -0
- package/dist/fantech/index.js +11 -0
- package/dist/fantech/index.js.map +1 -0
- package/dist/finalmouse/index.d.ts +41 -0
- package/dist/finalmouse/index.d.ts.map +1 -0
- package/dist/finalmouse/index.js +106 -0
- package/dist/finalmouse/index.js.map +1 -0
- package/dist/gearhub/index.d.ts +210 -0
- package/dist/gearhub/index.d.ts.map +1 -0
- package/dist/gearhub/index.js +282 -0
- package/dist/gearhub/index.js.map +1 -0
- package/dist/glorious/index.d.ts +89 -0
- package/dist/glorious/index.d.ts.map +1 -0
- package/dist/glorious/index.js +236 -0
- package/dist/glorious/index.js.map +1 -0
- package/dist/glorious-classic/index.d.ts +103 -0
- package/dist/glorious-classic/index.d.ts.map +1 -0
- package/dist/glorious-classic/index.js +304 -0
- package/dist/glorious-classic/index.js.map +1 -0
- package/dist/gwolves/index.d.ts +82 -0
- package/dist/gwolves/index.d.ts.map +1 -0
- package/dist/gwolves/index.js +197 -0
- package/dist/gwolves/index.js.map +1 -0
- package/dist/hyperx/index.d.ts +181 -0
- package/dist/hyperx/index.d.ts.map +1 -0
- package/dist/hyperx/index.js +303 -0
- package/dist/hyperx/index.js.map +1 -0
- package/dist/incott/index.d.ts +1067 -0
- package/dist/incott/index.d.ts.map +1 -0
- package/dist/incott/index.js +1482 -0
- package/dist/incott/index.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/keychron/index.d.ts +194 -0
- package/dist/keychron/index.d.ts.map +1 -0
- package/dist/keychron/index.js +341 -0
- package/dist/keychron/index.js.map +1 -0
- package/dist/ksnake/index.d.ts +157 -0
- package/dist/ksnake/index.d.ts.map +1 -0
- package/dist/ksnake/index.js +314 -0
- package/dist/ksnake/index.js.map +1 -0
- package/dist/lamzu/atlantis.d.ts +237 -0
- package/dist/lamzu/atlantis.d.ts.map +1 -0
- package/dist/lamzu/atlantis.js +263 -0
- package/dist/lamzu/atlantis.js.map +1 -0
- package/dist/lamzu/index.d.ts +60 -0
- package/dist/lamzu/index.d.ts.map +1 -0
- package/dist/lamzu/index.js +86 -0
- package/dist/lamzu/index.js.map +1 -0
- package/dist/logitech/controls.d.ts +138 -0
- package/dist/logitech/controls.d.ts.map +1 -0
- package/dist/logitech/controls.js +184 -0
- package/dist/logitech/controls.js.map +1 -0
- package/dist/logitech/friendly-name.d.ts +50 -0
- package/dist/logitech/friendly-name.d.ts.map +1 -0
- package/dist/logitech/friendly-name.js +74 -0
- package/dist/logitech/friendly-name.js.map +1 -0
- package/dist/logitech/haptics.d.ts +97 -0
- package/dist/logitech/haptics.d.ts.map +1 -0
- package/dist/logitech/haptics.js +116 -0
- package/dist/logitech/haptics.js.map +1 -0
- package/dist/logitech/hosts.d.ts +55 -0
- package/dist/logitech/hosts.d.ts.map +1 -0
- package/dist/logitech/hosts.js +80 -0
- package/dist/logitech/hosts.js.map +1 -0
- package/dist/logitech/index.d.ts +127 -0
- package/dist/logitech/index.d.ts.map +1 -0
- package/dist/logitech/index.js +233 -0
- package/dist/logitech/index.js.map +1 -0
- package/dist/logitech/wheel.d.ts +117 -0
- package/dist/logitech/wheel.d.ts.map +1 -0
- package/dist/logitech/wheel.js +133 -0
- package/dist/logitech/wheel.js.map +1 -0
- package/dist/mchose/a5-gen1.d.ts +38 -0
- package/dist/mchose/a5-gen1.d.ts.map +1 -0
- package/dist/mchose/a5-gen1.js +60 -0
- package/dist/mchose/a5-gen1.js.map +1 -0
- package/dist/mchose/buttons.d.ts +66 -0
- package/dist/mchose/buttons.d.ts.map +1 -0
- package/dist/mchose/buttons.js +184 -0
- package/dist/mchose/buttons.js.map +1 -0
- package/dist/mchose/dock.d.ts +77 -0
- package/dist/mchose/dock.d.ts.map +1 -0
- package/dist/mchose/dock.js +133 -0
- package/dist/mchose/dock.js.map +1 -0
- package/dist/mchose/index.d.ts +299 -0
- package/dist/mchose/index.d.ts.map +1 -0
- package/dist/mchose/index.js +429 -0
- package/dist/mchose/index.js.map +1 -0
- package/dist/mchose/v3-buttons.d.ts +64 -0
- package/dist/mchose/v3-buttons.d.ts.map +1 -0
- package/dist/mchose/v3-buttons.js +258 -0
- package/dist/mchose/v3-buttons.js.map +1 -0
- package/dist/mchose/v3.d.ts +380 -0
- package/dist/mchose/v3.d.ts.map +1 -0
- package/dist/mchose/v3.js +608 -0
- package/dist/mchose/v3.js.map +1 -0
- package/dist/microsoft/index.d.ts +19 -0
- package/dist/microsoft/index.d.ts.map +1 -0
- package/dist/microsoft/index.js +22 -0
- package/dist/microsoft/index.js.map +1 -0
- package/dist/moddo/index.d.ts +72 -0
- package/dist/moddo/index.d.ts.map +1 -0
- package/dist/moddo/index.js +147 -0
- package/dist/moddo/index.js.map +1 -0
- package/dist/ninjutso/index.d.ts +74 -0
- package/dist/ninjutso/index.d.ts.map +1 -0
- package/dist/ninjutso/index.js +133 -0
- package/dist/ninjutso/index.js.map +1 -0
- package/dist/orbital/index.d.ts +14 -0
- package/dist/orbital/index.d.ts.map +1 -0
- package/dist/orbital/index.js +19 -0
- package/dist/orbital/index.js.map +1 -0
- package/dist/pulsar/index.d.ts +81 -0
- package/dist/pulsar/index.d.ts.map +1 -0
- package/dist/pulsar/index.js +185 -0
- package/dist/pulsar/index.js.map +1 -0
- package/dist/rawm/index.d.ts +55 -0
- package/dist/rawm/index.d.ts.map +1 -0
- package/dist/rawm/index.js +229 -0
- package/dist/rawm/index.js.map +1 -0
- package/dist/razer/codec.d.ts +504 -0
- package/dist/razer/codec.d.ts.map +1 -0
- package/dist/razer/codec.js +648 -0
- package/dist/razer/codec.js.map +1 -0
- package/dist/razer/devices.d.ts +156 -0
- package/dist/razer/devices.d.ts.map +1 -0
- package/dist/razer/devices.js +540 -0
- package/dist/razer/devices.js.map +1 -0
- package/dist/razer/index.d.ts +2 -0
- package/dist/razer/index.d.ts.map +1 -0
- package/dist/razer/index.js +2 -0
- package/dist/razer/index.js.map +1 -0
- package/dist/razer/v4.d.ts +19 -0
- package/dist/razer/v4.d.ts.map +1 -0
- package/dist/razer/v4.js +51 -0
- package/dist/razer/v4.js.map +1 -0
- package/dist/steelseries/aerox3.d.ts +236 -0
- package/dist/steelseries/aerox3.d.ts.map +1 -0
- package/dist/steelseries/aerox3.js +311 -0
- package/dist/steelseries/aerox3.js.map +1 -0
- package/dist/steelseries/aerox5-wireless.d.ts +300 -0
- package/dist/steelseries/aerox5-wireless.d.ts.map +1 -0
- package/dist/steelseries/aerox5-wireless.js +389 -0
- package/dist/steelseries/aerox5-wireless.js.map +1 -0
- package/dist/steelseries/aerox5.d.ts +228 -0
- package/dist/steelseries/aerox5.d.ts.map +1 -0
- package/dist/steelseries/aerox5.js +294 -0
- package/dist/steelseries/aerox5.js.map +1 -0
- package/dist/steelseries/aerox9-wireless.d.ts +213 -0
- package/dist/steelseries/aerox9-wireless.d.ts.map +1 -0
- package/dist/steelseries/aerox9-wireless.js +305 -0
- package/dist/steelseries/aerox9-wireless.js.map +1 -0
- package/dist/steelseries/devices.d.ts +82 -0
- package/dist/steelseries/devices.d.ts.map +1 -0
- package/dist/steelseries/devices.js +310 -0
- package/dist/steelseries/devices.js.map +1 -0
- package/dist/steelseries/index.d.ts +13 -0
- package/dist/steelseries/index.d.ts.map +1 -0
- package/dist/steelseries/index.js +13 -0
- package/dist/steelseries/index.js.map +1 -0
- package/dist/steelseries/prime-mini-wireless.d.ts +253 -0
- package/dist/steelseries/prime-mini-wireless.d.ts.map +1 -0
- package/dist/steelseries/prime-mini-wireless.js +351 -0
- package/dist/steelseries/prime-mini-wireless.js.map +1 -0
- package/dist/steelseries/prime-plus.d.ts +179 -0
- package/dist/steelseries/prime-plus.d.ts.map +1 -0
- package/dist/steelseries/prime-plus.js +275 -0
- package/dist/steelseries/prime-plus.js.map +1 -0
- package/dist/steelseries/rival3-wireless.d.ts +222 -0
- package/dist/steelseries/rival3-wireless.d.ts.map +1 -0
- package/dist/steelseries/rival3-wireless.js +308 -0
- package/dist/steelseries/rival3-wireless.js.map +1 -0
- package/dist/steelseries/rival3.d.ts +99 -0
- package/dist/steelseries/rival3.d.ts.map +1 -0
- package/dist/steelseries/rival3.js +147 -0
- package/dist/steelseries/rival3.js.map +1 -0
- package/dist/steelseries/rival310.d.ts +230 -0
- package/dist/steelseries/rival310.d.ts.map +1 -0
- package/dist/steelseries/rival310.js +322 -0
- package/dist/steelseries/rival310.js.map +1 -0
- package/dist/steelseries/rival650.d.ts +215 -0
- package/dist/steelseries/rival650.d.ts.map +1 -0
- package/dist/steelseries/rival650.js +284 -0
- package/dist/steelseries/rival650.js.map +1 -0
- package/dist/steelseries/sensei-ten.d.ts +283 -0
- package/dist/steelseries/sensei-ten.d.ts.map +1 -0
- package/dist/steelseries/sensei-ten.js +389 -0
- package/dist/steelseries/sensei-ten.js.map +1 -0
- package/dist/teevolution/index.d.ts +211 -0
- package/dist/teevolution/index.d.ts.map +1 -0
- package/dist/teevolution/index.js +458 -0
- package/dist/teevolution/index.js.map +1 -0
- package/dist/valkyrie/index.d.ts +19 -0
- package/dist/valkyrie/index.d.ts.map +1 -0
- package/dist/valkyrie/index.js +43 -0
- package/dist/valkyrie/index.js.map +1 -0
- package/dist/valkyrie/settings.d.ts +28 -0
- package/dist/valkyrie/settings.d.ts.map +1 -0
- package/dist/valkyrie/settings.js +84 -0
- package/dist/valkyrie/settings.js.map +1 -0
- package/dist/vgn/index.d.ts +59 -0
- package/dist/vgn/index.d.ts.map +1 -0
- package/dist/vgn/index.js +165 -0
- package/dist/vgn/index.js.map +1 -0
- package/dist/wallhack/index.d.ts +165 -0
- package/dist/wallhack/index.d.ts.map +1 -0
- package/dist/wallhack/index.js +226 -0
- package/dist/wallhack/index.js.map +1 -0
- package/dist/wlmouse/index.d.ts +4 -0
- package/dist/wlmouse/index.d.ts.map +1 -0
- package/dist/wlmouse/index.js +7 -0
- package/dist/wlmouse/index.js.map +1 -0
- package/dist/wooting/index.d.ts +225 -0
- package/dist/wooting/index.d.ts.map +1 -0
- package/dist/wooting/index.js +296 -0
- package/dist/wooting/index.js.map +1 -0
- package/dist/zaunkoenig/index.d.ts +49 -0
- package/dist/zaunkoenig/index.d.ts.map +1 -0
- package/dist/zaunkoenig/index.js +127 -0
- package/dist/zaunkoenig/index.js.map +1 -0
- 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
|