diff --git a/README.md b/README.md index 59e172d..06be9b2 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# Spacemouse +# SpaceMouse and SpaceNavigator connection library [![Node CI](https://github.com/nytamin/spacemouse/actions/workflows/lint-and-test.yml/badge.svg)](https://github.com/nytamin/spacemouse/actions/workflows/lint-and-test.yml) -A Node.js module to interact with the [3DConnection space mice](https://3dconnexion.com). +A Node.js module to interact with the [3Dconnexion devices](https://3dconnexion.com), such as the SpaceMouse and SpaceNavigator. -Licence: MIT +This repository is not affiliated with 3Dconnexion in any way. + +License: MIT ## Demo @@ -40,44 +42,37 @@ 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 space mice simultaneously, you might also have to set your env-var [UV_THREADPOOL_SIZE](http://docs.libuv.org/en/v1.x/threadpool.html): +Note: If you need more than 4 devices simultaneously, you might also have to set your env-var [UV_THREADPOOL_SIZE](http://docs.libuv.org/en/v1.x/threadpool.html): ```javascript var { env } = require('process') env.UV_THREADPOOL_SIZE = 8 // Allow up to 8 devices ``` -## BREAKING CHANGES - -Please note that version `2.0.0` is a _BREAKING CHANGE_, as most of the API have changed. -If you're upgrading from `<2.0.0`, please read the [_Migrations_](#Migrations) section below. - ## Getting started - Node.js ### Watch for connected SpaceMouse (recommended) This is the recommended way to use this library, to automatically be connected or reconnected to the device. -_Note: The watcher depends on the [node-usb](https://github.com/node-usb/node-usb) library, which might be unsupported on some platforms._ +_Note: The watcher uses the [node-usb](https://github.com/node-usb/node-usb) library, which might be unsupported on some platforms. If it is not supported, it can use polling as fallback._ ```javascript const { SpaceMouseWatcher } = require('spacemouse-node') /* This example connects to any connected SpaceMouse devices and logs - whenever a button is pressed or analog thing is moved + whenever the mouse is moved or a button is pressed. */ -// Set up the watcher: +// Set up the watcher for SpaceMouse: const watcher = new SpaceMouseWatcher({ - // automaticUnitIdMode: false - // usePolling: false + // 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`) @@ -89,38 +84,21 @@ watcher.on('connected', (spaceMouse) => { spaceMouse.on('error', (...errs) => { console.log('SpaceMouse error:', ...errs) }) - - // Listen to pressed buttons: - spaceMouse.on('down', (keyIndex, metadata) => { - console.log('Button pressed ', keyIndex, metadata) - - // Light up a button when pressed: - spaceMouse.setBacklight(keyIndex, 'red') - }) - // Listen to released buttons: - spaceMouse.on('up', (keyIndex, metadata) => { - console.log('Button released', keyIndex, metadata) - - // Turn off button light when released: - spaceMouse.setBacklight(keyIndex, false) - }) - - // Listen to jog wheel changes: - spaceMouse.on('jog', (index, deltaPos, metadata) => { - console.log(`Jog ${index} position has changed`, deltaPos, metadata) + // Listen to Rotation changes: + spaceMouse.on('rotate', (rotate) => { + console.log(`Rotate ${JSON.stringify(rotate)}`) }) - // Listen to shuttle changes: - spaceMouse.on('shuttle', (index, shuttlePos, metadata) => { - console.log(`Shuttle ${index} position has changed`, shuttlePos, metadata) + // Listen to Translation changes: + spaceMouse.on('translate', (translate) => { + console.log(`Translate ${JSON.stringify(translate)}`) }) - // Listen to joystick changes: - - spaceMouse.on('joystick', (index, position, metadata) => { - console.log(`Joystick ${index} position has changed`, position, metadata) // {x, y, z} + // Listen to pressed buttons: + spaceMouse.on('down', (keyIndex) => { + console.log('Button pressed ', keyIndex) }) - // Listen to t-bar changes: - spaceMouse.on('tbar', (index, position, metadata) => { - console.log(`T-bar ${index} position has changed`, position, metadata) + // Listen to released buttons: + spaceMouse.on('up', (keyIndex) => { + console.log('Button released', keyIndex) }) }) @@ -131,29 +109,28 @@ watcher.on('connected', (spaceMouse) => { ### Connect to a devices manually ```javascript -const { setupSpaceMouse } = require('spaceMouse') +const { setupSpaceMouse } = require('spacemouse-node') /* - This example shows how to use SpaceMouse.setupSpaceMouse() + This example shows how to use setupSpaceMouse() directly, instead of going via SpaceMouseWatcher() */ -// Connect to an spaceMouse-device: +// Connect to an SpaceMouse-device: setupSpaceMouse() .then((spaceMouse) => { + console.log(`Connected to ${spaceMouse.info.name}`) spaceMouse.on('disconnected', () => { - console.log(`SpaceMouse device of type ${spaceMouse.info.name} was disconnected`) - // Clean up stuff + console.log(`Disconnected!`) spaceMouse.removeAllListeners() }) - spaceMouse.on('error', (...errs) => { - console.log('SpaceMouse error:', ...errs) + spaceMouse.on('error', (...args) => { + console.log('SpaceMouse error:', ...args) }) - - spaceMouse.on('down', (keyIndex, metadata) => { - console.log('Button pressed', keyIndex, metadata) + // Listen to Rotation changes: + spaceMouse.on('rotate', (rotate) => { + console.log(`Rotate ${JSON.stringify(rotate)}`) }) - // ... }) .catch(console.log) // Handle error @@ -162,14 +139,25 @@ setupSpaceMouse() or ```javascript -const { listAllConnectedDevices, setupSpaceMouse } = require('spaceMouse') +const { listAllConnectedDevices, setupSpaceMouse } = require('spacemouse-node') -// List and connect to all spaceMouse-devices: +// 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 @@ -190,56 +178,43 @@ 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: ```javascript -const { SpaceMouseWatcher } = require('spaceMouse') +const { SpaceMouseWatcher } = require('spacemouse-node') const watcher = new SpaceMouseWatcher({ - // automaticUnitIdMode: false // usePolling: false - // pollingInterval= 1000 + // pollingInterval: 1000 }) watcher.on('error', (e) => { console.log('Error in SpaceMouseWatcher', e) }) watcher.on('connected', (spaceMouse) => { - // spaceMouse connected... + // SpaceMouse connected... }) ``` -#### automaticUnitIdMode - -When this is set to `true`, the SpaceMouseWatcher will enable the `"reconnected"` event for the spaceMice. - -By default, there is no unique identifier stored on the SpaceMouse device that can be used to differ between -"reconnecting a previously known device" or "connecting a new device". -The `automaticUnitIdMode` fixes this by writing a pseudo-unique id to the `unitId` of the device, -if none has been set previously. - #### usePolling -When this is set, the SpaceMouseWatcher will not use the `usb` library for detecting connected devices, +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 slower detection of new devices. +This is compatible with more systems and OS:es, but might result in higher system usage, slower detection of new devices. -### spaceMouse Events +### SpaceMouse Events ```javascript // Example: -spaceMouse.on('down', (keyIndex, metadata) => { - console.log('Button pressed', keyIndex, metadata) +spaceMouse.on('rotate', (rotation) => { + console.log(rotation) }) ``` -| Event | Description | -| ---------------- | ---------------------------------------------------------------------------------------------------------------- | -| `"error"` | Triggered on error. Emitted with `(error)`. | -| `"down"`, `"up"` | Triggered when a button is pressed/released. Emitted with `(keyIndex, metadata)`. | -| `"jog"` | Triggered when the jog wheel is moved. Emitted with `(index, jogValue, metadata)` | -| `"shuttle"` | Triggered when the shuttle is moved. Emitted with `(index, shuttleValue, metadata)` | -| `"joystick"` | Triggered when the joystick is moved. Emitted with `(index, {x, y, z, deltaZ})` | -| `"tbar"` | Triggered when the T-bar is moved. Emitted with `(index, tbarPosition, metadata)` | -| `"disconnected"` | Triggered when device is disconnected. | -| `"reconnected"` | Triggered when device is reconnection. Only emitted when [automaticUnitIdMode](#automaticUnitIdMode) is enabled. | +| 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)` | -### spaceMouse Methods +### SpaceMouse Methods **Setting the backlight of a button** @@ -388,24 +363,24 @@ To install Yarn, just run `npm install -g yarn`. 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. ```bash -# To set up the spaceMouse-repo for linking: +# 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 +# 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: +# Set up your local test repo to used the linked SpaceMouse libraries: cd your/test/repo -yarn add spaceMouse -yarn link spaceMouse +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 +yarn unlink spacemouse-node yarn unlink @spacemouse-lib/core yarn --force # So that it reinstalls the ordinary dependencies ``` @@ -417,14 +392,14 @@ If you have any questions or want to report a bug, [please open an issue at Gith 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](https://github.com/nytamin/spacemouse/issues/new) to announce it first, and spark discussions. -### Coding style and tests +#### Coding style and tests 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: ```bash -yarn # To ensure the right dependencies are installed +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. diff --git a/packages/core/src/SpaceMouse.ts b/packages/core/src/SpaceMouse.ts index 56f2371..50c462a 100644 --- a/packages/core/src/SpaceMouse.ts +++ b/packages/core/src/SpaceMouse.ts @@ -28,7 +28,6 @@ export class SpaceMouse extends EventEmitter { private _initialized = false private _disconnected = false - private closed = false /** Vendor ids for the SpaceMouse devices */ static get vendorIds(): number[] { @@ -134,7 +133,6 @@ export class SpaceMouse extends EventEmitter { } /** Closes the device. Subsequent commands will raise errors. */ public async close(): Promise { - this.closed = true await this._handleDeviceDisconnected() } @@ -170,21 +168,6 @@ export class SpaceMouse extends EventEmitter { this.emit('disconnected') } } - /** (Internal function) Called when there has been detected that a device has been reconnected */ - public async _handleDeviceReconnected(device: HIDDevice, deviceInfo: DeviceInfo): Promise { - if (this.closed) return - - if (this._disconnected) { - this._disconnected = false - - // Re-vitalize: - this._device = device - this.product = this._setupDevice(deviceInfo) - await this.init() - - this.emit('reconnected') - } - } public get hidDevice(): HIDDevice { return this._device } diff --git a/packages/core/src/api.ts b/packages/core/src/api.ts index 8f8d1dc..a24f108 100644 --- a/packages/core/src/api.ts +++ b/packages/core/src/api.ts @@ -18,15 +18,14 @@ export interface Rotation { export interface SpaceMouseEvents { // Note: This interface defines strong typings for any events that are emitted by the SpaceMouse class. + disconnected: () => void + error: (err: any) => void + translate: (translation: Translation) => void rotate: (rotation: Rotation) => void - down: (keyIndex: number) => void - up: (keyIndex: number) => void - - disconnected: () => void - reconnected: () => void - error: (err: any) => void + down: (buttonIndex: number) => void + up: (buttonIndex: number) => void } export interface SpaceMouseInfo { /** Name of the device */ diff --git a/packages/node/examples/basic-log-all-events.js b/packages/node/examples/basic-log-all-events.js index 5c1b906..d1f7383 100644 --- a/packages/node/examples/basic-log-all-events.js +++ b/packages/node/examples/basic-log-all-events.js @@ -1,17 +1,15 @@ const { SpaceMouseWatcher } = require('spacemouse-node') - /* This example connects to any connected SpaceMouse devices and logs - whenever a button is pressed or analog thing is moved + whenever the mouse is moved or a button is pressed. */ -// Set up the watcher for spaceMouse: +// Set up the watcher for SpaceMouse: const watcher = new SpaceMouseWatcher({ - // usePolling: false + // usePolling: false // To be used if node-usb is not supported // pollingInterval= 1000 }) - watcher.on('error', (e) => { console.log('Error in SpaceMouseWatcher', e) }) @@ -26,15 +24,6 @@ watcher.on('connected', (spaceMouse) => { spaceMouse.on('error', (...errs) => { console.log('SpaceMouse error:', ...errs) }) - - // 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) - }) // Listen to Rotation changes: spaceMouse.on('rotate', (rotate) => { console.log(`Rotate ${JSON.stringify(rotate)}`) @@ -43,6 +32,15 @@ watcher.on('connected', (spaceMouse) => { 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 diff --git a/packages/node/examples/manually-connect.js b/packages/node/examples/manually-connect.js index 55a7003..56ac8c0 100644 --- a/packages/node/examples/manually-connect.js +++ b/packages/node/examples/manually-connect.js @@ -1,53 +1,47 @@ -// const { setupSpaceMouse, listAllConnectedDevices } = require('spacemouse-node') -const { setupSpaceMouse, listAllConnectedDevices } = require('../dist')// nocommit tmp +const { setupSpaceMouse, listAllConnectedDevices } = require('spacemouse-node') /* This example shows how to use setupSpaceMouse() directly, instead of going via SpaceMouseWatcher() */ -// Connect to an spaceMouse-device: +// Connect to an SpaceMouse-device: setupSpaceMouse() .then((spaceMouse) => { + console.log(`Connected to ${spaceMouse.info.name}`) spaceMouse.on('disconnected', () => { - console.log(`SpaceMouse device of type ${spaceMouse.info.name} was disconnected`) - // Clean up stuff + console.log(`Disconnected!`) spaceMouse.removeAllListeners() }) - spaceMouse.on('error', (...errs) => { - console.log('SpaceMouse error:', ...errs) + spaceMouse.on('error', (...args) => { + console.log('SpaceMouse error:', ...args) }) - - spaceMouse.on('down', (keyIndex, metadata) => { - console.log('Button pressed', keyIndex, metadata) + // Listen to Rotation changes: + spaceMouse.on('rotate', (rotate) => { + console.log(`Rotate ${JSON.stringify(rotate)}`) }) - // ... }) .catch(console.log) // Handle error -// List and connect to all spaceMouse-devices: +// List and connect to all SpaceMouse-devices: listAllConnectedDevices().forEach((connectedDevice) => { setupSpaceMouse(connectedDevice) .then((spaceMouse) => { console.log(`Connected to ${spaceMouse.info.name}`) - - // Listen to pressed buttons: - spaceMouse.on('down', (keyIndex) => { - console.log('Button pressed ', keyIndex) + spaceMouse.on('disconnected', () => { + console.log(`Disconnected!`) + spaceMouse.removeAllListeners() }) - // Listen to released buttons: - spaceMouse.on('up', (keyIndex) => { - console.log('Button released', keyIndex) + spaceMouse.on('error', (...args) => { + console.log('SpaceMouse error:', ...args) }) + // 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)}`) + spaceMouse.on('rotate', (rotate) => { + console.log(`Rotate ${JSON.stringify(rotate)}`) }) + // ... }) .catch(console.log) // Handle error }) diff --git a/packages/webhid-demo/README.md b/packages/webhid-demo/README.md index a1866fd..eabf1d1 100644 --- a/packages/webhid-demo/README.md +++ b/packages/webhid-demo/README.md @@ -1,3 +1,5 @@ # SpaceMouse - WebHID -This folder contains an example implementation for the WebHID-version of the spacemouse-library. +This folder contains an example implementation for the WebHID-version of the SpaceMouse-library. + +[You can find the demo here.](https://nytamin.github.io/spacemouse/) diff --git a/packages/webhid-demo/public/index.html b/packages/webhid-demo/public/index.html index be97b63..9da9856 100644 --- a/packages/webhid-demo/public/index.html +++ b/packages/webhid-demo/public/index.html @@ -6,7 +6,13 @@

SpaceMouse WebHID demo

-

Based on spaceMouse

+ +

+ This is a demo of the + spacemouse-webhid library.
+ Source code for this demo is available + here. +

Getting started

Requirements: