Skip to content

Commit

Permalink
chore: docs and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nytamin committed Nov 14, 2023
1 parent 34e7338 commit 57b3975
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 159 deletions.
165 changes: 70 additions & 95 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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`)

Expand All @@ -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)
})
})

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.<br>Emitted with `(error)`. |
| `"disconnected"` | Triggered when device is disconnected. |
| `"rotate"` | Triggered when the mouse is rotated.<br>Emitted with `(rotation: {pitch: number, roll: number, yaw: number})` |
| `"translate"` | Triggered when the mouse is moved.<br>Emitted with `(translation: {x: number, y: number, z: number})` |
| `"down"`, `"up"` | Triggered when a button is pressed / released.<br>Emitted with `(buttonIndex: number)` |
### spaceMouse Methods
### SpaceMouse Methods
**Setting the backlight of a button**
Expand Down Expand Up @@ -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
```
Expand All @@ -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.
Expand Down
17 changes: 0 additions & 17 deletions packages/core/src/SpaceMouse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[] {
Expand Down Expand Up @@ -134,7 +133,6 @@ export class SpaceMouse extends EventEmitter {
}
/** Closes the device. Subsequent commands will raise errors. */
public async close(): Promise<void> {
this.closed = true
await this._handleDeviceDisconnected()
}

Expand Down Expand Up @@ -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<void> {
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
}
Expand Down
11 changes: 5 additions & 6 deletions packages/core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit 57b3975

Please sign in to comment.