A Node.js module to interact with the 3Dconnexion devices, such as the SpaceMouse and SpaceNavigator.
This repository is not affiliated with 3Dconnexion in any way.
License: MIT
If you are using a browser that supports WebHID, you can try out the library right away, in the browser: Demo.
Some of the devices supported by this library are:
- SpaceNavigator
- SpaceMouse Wireless
- SpaceMouse Compact
- SpaceMouse Module
- SpaceMouse Pro
- SpaceMouse Pro Wireless
- SpacePilot PRO
- SpaceMouse Enterprise
- CadMouse
- CadMouse Wireless
- CadMouse Pro Wireless
- CadMouse Compact
- CadMouse Pro
- CadMouse Compact Wireless
See the full list in products.ts.
$ npm install --save spacemouse-node
or
$ yarn add spacemouse-node
$ npm install --save spacemouse-webhid
or
$ yarn add spacemouse-webhid
On linux, the udev
subsystem blocks access for non-root users to the SpaceMouse without some special configuration. Save the following to /etc/udev/rules.d/50-spacemouse.rules
and reload the rules with sudo udevadm control --reload-rules
SUBSYSTEM=="input", GROUP="input", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0x46d", MODE:="666", GROUP="plugdev"
KERNEL=="hidraw*", ATTRS{idVendor}=="0x46d", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0x256f", MODE:="666", GROUP="plugdev"
KERNEL=="hidraw*", ATTRS{idVendor}=="0x256f", MODE="0666", GROUP="plugdev"
Note: If you need more than 4 devices simultaneously, you might also have to set your env-var UV_THREADPOOL_SIZE:
var { env } = require('process')
env.UV_THREADPOOL_SIZE = 8 // Allow up to 8 devices
This is the recommended way to use this library, to automatically be connected or reconnected to the device.
Note: The watcher uses the node-usb library, which might be unsupported on some platforms. If it is not supported, it can use polling as fallback.
const { SpaceMouseWatcher } = require('spacemouse-node') // or spacemouse-webhid in browser
/*
This example connects to any connected SpaceMouse devices and logs
whenever the mouse is moved or a button is pressed.
*/
// Set up the watcher for SpaceMouse:
const watcher = new SpaceMouseWatcher({
// usePolling: false // To be used if node-usb is not supported
// pollingInterval= 1000
})
watcher.on('error', (e) => {
console.log('Error in SpaceMouseWatcher', e)
})
watcher.on('connected', (spaceMouse) => {
console.log(`SpaceMouse device of type ${spaceMouse.info.name} connected`)
spaceMouse.on('disconnected', () => {
console.log(`SpaceMouse device of type ${spaceMouse.info.name} was disconnected`)
// Clean up stuff
spaceMouse.removeAllListeners()
})
spaceMouse.on('error', (...errs) => {
console.log('SpaceMouse error:', ...errs)
})
// Listen to Rotation changes:
spaceMouse.on('rotate', (rotate) => {
console.log(`Rotate ${JSON.stringify(rotate)}`)
})
// Listen to Translation changes:
spaceMouse.on('translate', (translate) => {
console.log(`Translate ${JSON.stringify(translate)}`)
})
// Listen to pressed buttons:
spaceMouse.on('down', (keyIndex) => {
console.log('Button pressed ', keyIndex)
})
// Listen to released buttons:
spaceMouse.on('up', (keyIndex) => {
console.log('Button released', keyIndex)
})
})
// To stop watching, call
// watcher.stop().catch(console.error)
const { setupSpaceMouse } = require('spacemouse-node') // or spacemouse-webhid in browser
/*
This example shows how to use setupSpaceMouse()
directly, instead of going via SpaceMouseWatcher()
*/
// Connect to an SpaceMouse-device:
setupSpaceMouse()
.then((spaceMouse) => {
console.log(`Connected to ${spaceMouse.info.name}`)
spaceMouse.on('disconnected', () => {
console.log(`Disconnected!`)
spaceMouse.removeAllListeners()
})
spaceMouse.on('error', (...args) => {
console.log('SpaceMouse error:', ...args)
})
// Listen to Rotation changes:
spaceMouse.on('rotate', (rotate) => {
console.log(`Rotate ${JSON.stringify(rotate)}`)
})
// ...
})
.catch(console.log) // Handle error
or
const { listAllConnectedDevices, setupSpaceMouse } = require('spacemouse-node')
// List and connect to all SpaceMouse-devices:
listAllConnectedDevices().forEach((connectedDevice) => {
setupSpaceMouse(connectedDevice)
.then((spaceMouse) => {
console.log(`Connected to ${spaceMouse.info.name}`)
spaceMouse.on('disconnected', () => {
console.log(`Disconnected!`)
spaceMouse.removeAllListeners()
})
spaceMouse.on('error', (...args) => {
console.log('SpaceMouse error:', ...args)
})
// Listen to Rotation changes:
spaceMouse.on('rotate', (rotate) => {
console.log(`Rotate ${JSON.stringify(rotate)}`)
})
// ...
})
.catch(console.log) // Handle error
See the example implementation at packages/webhid-demo.
If you are using a Chromium v89+ based browser, you can try out the webhid demo.
The SpaceMouseWatcher has a few different options that can be set upon initialization:
const { SpaceMouseWatcher } = require('spacemouse-node')
const watcher = new SpaceMouseWatcher({
// usePolling: false
// pollingInterval: 1000
})
watcher.on('error', (e) => {
console.log('Error in SpaceMouseWatcher', e)
})
watcher.on('connected', (spaceMouse) => {
// SpaceMouse connected...
})
When this is set, the SpaceMouseWatcher will not use the node-usb
library for detecting connected devices,
but instead resort to polling at an interval (pollingInterval
).
This is compatible with more systems and OS:es, but might result in higher system usage, slower detection of new devices.
// Example:
spaceMouse.on('rotate', (rotation) => {
console.log(rotation)
})
Event | Description |
---|---|
"error" |
Triggered on error. Emitted with (error) . |
"disconnected" |
Triggered when device is disconnected. |
"rotate" |
Triggered when the mouse is rotated. Emitted with (rotation: {pitch: number, roll: number, yaw: number}) |
"translate" |
Triggered when the mouse is moved. Emitted with (translation: {x: number, y: number, z: number}) |
"down" , "up" |
Triggered when a button is pressed / released. Emitted with (buttonIndex: number) |
See the SpaceMouse-class for more functionality.
This is a mono-repo, using Lerna and Yarn.
This repo is using Yarn. If you don't want to use it, replace yarn xyz
with npm run xyz
below.
To install Yarn, just run npm install -g yarn
.
- Clone the repo and
cd
into it. - Install all dependencies:
yarn
. - Do an initial build:
yarn build
If you'd like to run and test your local changes, yarn link
is a useful tool to symlink your local spaceMouse
dependency into your test repo.
# To set up the SpaceMouse-repo for linking:
cd your/spaceMouse/repo
yarn lerna exec yarn link # This runs "yarn link" in all of the mono-repo packages
yarn build
# Every time after you've made any changes to the SpaceMouse-repo you need to rebuild
cd your/spaceMouse/repo
yarn build
# Set up your local test repo to used the linked SpaceMouse libraries:
cd your/test/repo
yarn add spacemouse-node
yarn link spacemouse-node
yarn link @spacemouse-lib/core
# To unlink the spacemouse-lib from your local test repo:
cd your/test/repo
yarn unlink spacemouse-node
yarn unlink @spacemouse-lib/core
yarn --force # So that it reinstalls the ordinary dependencies
If you have any questions or want to report a bug, please open an issue at Github.
If you want to contribute a bug fix or improvement, we'd happily accept Pull Requests. (If you're planning something big, please open an issue to announce it first, and spark discussions.
Please follow the same coding style as the rest of the repository as you type. :)
Before committing your code to git, be sure to run these commands:
yarn # To ensure the right dependencies are installed and yarn.lock is updated
yarn build # To ensure that there are no syntax or build errors
yarn lint # To ensure that the formatting follows the right rules
yarn test # To ensure that your code passes the unit tests.
If you're adding a new functionality, adding unit tests for it is much appreciated.
- Push your changes to any branch
- Trigger a run of CI: publish-nightly
- Update the branch (preferably the master branch)
yarn release:bump-prerelease
and push the changes (including the tag)- Trigger a run of CI: publish-prerelease
- Update the the master branch
yarn release:bump-release
and push the changes (including the tag)- Trigger a run of CI: publish-release to publish to NPM.
- Trigger a run of CI: publish-demo to update the docs.
By contributing, you agree that your contributions will be licensed under the MIT License.