buttplug 3.2.2 → 4.0.1
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/.eslintrc.js +25 -25
- package/.jscsrc +2 -2
- package/.jshintrc +5 -5
- package/.prettierrc.json +3 -3
- package/.yarnrc.yml +5 -5
- package/CHANGELOG.md +591 -577
- package/LICENSE +27 -27
- package/README.md +105 -97
- package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js +6 -9
- package/dist/main/src/client/ButtplugBrowserWebsocketClientConnector.js.map +1 -1
- package/dist/main/src/client/{Client.d.ts → ButtplugClient.d.ts} +3 -4
- package/dist/main/src/client/ButtplugClient.js +232 -0
- package/dist/main/src/client/ButtplugClient.js.map +1 -0
- package/dist/main/src/client/ButtplugClientConnectorException.js +17 -7
- package/dist/main/src/client/ButtplugClientConnectorException.js.map +1 -1
- package/dist/main/src/client/ButtplugClientDevice.d.ts +13 -28
- package/dist/main/src/client/ButtplugClientDevice.js +105 -247
- package/dist/main/src/client/ButtplugClientDevice.js.map +1 -1
- package/dist/main/src/client/ButtplugClientDeviceCommand.d.ts +42 -0
- package/dist/main/src/client/ButtplugClientDeviceCommand.js +105 -0
- package/dist/main/src/client/ButtplugClientDeviceCommand.js.map +1 -0
- package/dist/main/src/client/ButtplugClientDeviceFeature.d.ts +18 -0
- package/dist/main/src/client/ButtplugClientDeviceFeature.js +166 -0
- package/dist/main/src/client/ButtplugClientDeviceFeature.js.map +1 -0
- package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -8
- package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js +1 -4
- package/dist/main/src/client/ButtplugNodeWebsocketClientConnector.js.map +1 -1
- package/dist/main/src/core/Exceptions.js +27 -9
- package/dist/main/src/core/Exceptions.js.map +1 -1
- package/dist/main/src/core/Logging.js +12 -6
- package/dist/main/src/core/Logging.js.map +1 -1
- package/dist/main/src/core/Messages.d.ts +119 -230
- package/dist/main/src/core/Messages.js +50 -404
- package/dist/main/src/core/Messages.js.map +1 -1
- package/dist/main/src/index.d.ts +2 -2
- package/dist/main/src/index.js +4 -2
- package/dist/main/src/index.js.map +1 -1
- package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js +40 -52
- package/dist/main/src/utils/ButtplugBrowserWebsocketConnector.js.map +1 -1
- package/dist/main/src/utils/ButtplugMessageSorter.js +27 -15
- package/dist/main/src/utils/ButtplugMessageSorter.js.map +1 -1
- package/dist/main/src/utils/Utils.js +1 -2
- package/dist/main/src/utils/Utils.js.map +1 -1
- package/dist/web/buttplug.js +1 -38
- package/dist/web/buttplug.mjs +595 -1984
- package/dist/web/client/ButtplugBrowserWebsocketClientConnector.d.ts +0 -7
- package/dist/web/client/{Client.d.ts → ButtplugClient.d.ts} +3 -11
- package/dist/web/client/ButtplugClientConnectorException.d.ts +0 -7
- package/dist/web/client/ButtplugClientDevice.d.ts +14 -29
- package/dist/web/client/ButtplugClientDeviceCommand.d.ts +42 -0
- package/dist/web/client/ButtplugClientDeviceFeature.d.ts +18 -0
- package/dist/web/client/ButtplugNodeWebsocketClientConnector.d.ts +1 -15
- package/dist/web/client/IButtplugClientConnector.d.ts +0 -7
- package/dist/web/core/Exceptions.d.ts +1 -1
- package/dist/web/core/Logging.d.ts +0 -7
- package/dist/web/core/Messages.d.ts +119 -229
- package/dist/web/index.d.ts +2 -2
- package/dist/web/utils/ButtplugBrowserWebsocketConnector.d.ts +0 -7
- package/examples/node/SYNC_MANIFEST.md +105 -0
- package/examples/node/application-example.ts +213 -0
- package/examples/node/async-example.ts +124 -0
- package/examples/node/connection-example.ts +76 -0
- package/examples/node/device-control-example.ts +131 -0
- package/examples/node/device-enumeration-example.ts +86 -0
- package/examples/node/device-info-example.ts +131 -0
- package/examples/node/errors-example.ts +166 -0
- package/examples/node/package-lock.json +281 -0
- package/examples/node/package.json +25 -0
- package/examples/node/remote-connector-example.ts +84 -0
- package/examples/node/tsconfig.json +14 -0
- package/examples/web/application-example.js +197 -0
- package/examples/web/async-example.js +90 -0
- package/examples/web/device-control-example.js +87 -0
- package/examples/web/device-enumeration-example.js +49 -0
- package/examples/web/device-info-example.js +100 -0
- package/examples/web/errors-example.js +110 -0
- package/examples/web/index.html +55 -0
- package/examples/web/logging.js +42 -0
- package/examples/web/ping-timeout-example.js +59 -0
- package/examples/web/remote-connector-example.js +68 -0
- package/node-test.js +24 -0
- package/node-test.ts +23 -5
- package/package.json +85 -87
- package/src/client/ButtplugBrowserWebsocketClientConnector.ts +25 -25
- package/src/client/ButtplugClient.ts +242 -0
- package/src/client/ButtplugClientConnectorException.ts +16 -16
- package/src/client/ButtplugClientDevice.ts +178 -401
- package/src/client/ButtplugClientDeviceCommand.ts +112 -0
- package/src/client/ButtplugClientDeviceFeature.ts +138 -0
- package/src/client/ButtplugNodeWebsocketClientConnector.ts +17 -17
- package/src/client/IButtplugClientConnector.ts +18 -18
- package/src/core/Exceptions.ts +107 -101
- package/src/core/Logging.ts +197 -197
- package/src/core/Messages.ts +205 -480
- package/src/core/index.d.ts +4 -4
- package/src/index.ts +21 -19
- package/src/utils/ButtplugBrowserWebsocketConnector.ts +89 -89
- package/src/utils/ButtplugMessageSorter.ts +66 -65
- package/src/utils/Utils.ts +3 -3
- package/tsconfig.json +22 -22
- package/tsfmt.json +14 -14
- package/tslint.json +27 -27
- package/typedocconfig.js +6 -6
- package/vite.config.ts +26 -26
- package/dist/main/src/client/Client.js +0 -242
- package/dist/main/src/client/Client.js.map +0 -1
- package/dist/main/src/core/MessageUtils.d.ts +0 -10
- package/dist/main/src/core/MessageUtils.js +0 -65
- package/dist/main/src/core/MessageUtils.js.map +0 -1
- package/dist/web/core/MessageUtils.d.ts +0 -10
- package/doc/.nojekyll +0 -1
- package/doc/assets/highlight.css +0 -22
- package/doc/assets/main.js +0 -58
- package/doc/assets/search.js +0 -1
- package/doc/assets/style.css +0 -1280
- package/doc/classes/ButtplugBrowserWebsocketClientConnector.html +0 -234
- package/doc/classes/ButtplugClient.html +0 -331
- package/doc/classes/ButtplugClientConnectorException.html +0 -216
- package/doc/classes/ButtplugClientDevice.html +0 -489
- package/doc/classes/ButtplugDeviceError.html +0 -218
- package/doc/classes/ButtplugDeviceMessage.html +0 -165
- package/doc/classes/ButtplugError.html +0 -220
- package/doc/classes/ButtplugInitError.html +0 -218
- package/doc/classes/ButtplugLogger.html +0 -288
- package/doc/classes/ButtplugMessage.html +0 -147
- package/doc/classes/ButtplugMessageError.html +0 -218
- package/doc/classes/ButtplugMessageSorter.html +0 -128
- package/doc/classes/ButtplugNodeWebsocketClientConnector.html +0 -239
- package/doc/classes/ButtplugPingError.html +0 -218
- package/doc/classes/ButtplugSystemMessage.html +0 -150
- package/doc/classes/ButtplugUnknownError.html +0 -218
- package/doc/classes/DeviceAdded.html +0 -186
- package/doc/classes/DeviceInfo.html +0 -114
- package/doc/classes/DeviceList.html +0 -160
- package/doc/classes/DeviceRemoved.html +0 -158
- package/doc/classes/Error.html +0 -179
- package/doc/classes/GenericDeviceMessageAttributes.html +0 -107
- package/doc/classes/GenericMessageSubcommand.html +0 -90
- package/doc/classes/LinearCmd.html +0 -187
- package/doc/classes/LogMessage.html +0 -134
- package/doc/classes/MessageAttributes.html +0 -160
- package/doc/classes/Ok.html +0 -151
- package/doc/classes/Ping.html +0 -151
- package/doc/classes/RawDeviceMessageAttributes.html +0 -86
- package/doc/classes/RawReadCmd.html +0 -188
- package/doc/classes/RawReading.html +0 -179
- package/doc/classes/RawSubscribeCmd.html +0 -170
- package/doc/classes/RawUnsubscribeCmd.html +0 -170
- package/doc/classes/RawWriteCmd.html +0 -188
- package/doc/classes/RequestDeviceList.html +0 -151
- package/doc/classes/RequestServerInfo.html +0 -169
- package/doc/classes/RotateCmd.html +0 -187
- package/doc/classes/RotateSubcommand.html +0 -108
- package/doc/classes/ScalarCmd.html +0 -170
- package/doc/classes/ScalarSubcommand.html +0 -108
- package/doc/classes/ScanningFinished.html +0 -146
- package/doc/classes/SensorDeviceMessageAttributes.html +0 -107
- package/doc/classes/SensorReadCmd.html +0 -179
- package/doc/classes/SensorReading.html +0 -188
- package/doc/classes/ServerInfo.html +0 -178
- package/doc/classes/StartScanning.html +0 -151
- package/doc/classes/StopAllDevices.html +0 -151
- package/doc/classes/StopDeviceCmd.html +0 -161
- package/doc/classes/StopScanning.html +0 -151
- package/doc/classes/VectorSubcommand.html +0 -108
- package/doc/enums/ActuatorType.html +0 -104
- package/doc/enums/ButtplugLogLevel.html +0 -97
- package/doc/enums/ErrorClass.html +0 -90
- package/doc/enums/SensorType.html +0 -90
- package/doc/functions/FromJSON.html +0 -113
- package/doc/index.html +0 -184
- package/doc/interfaces/IButtplugClientConnector.html +0 -137
- package/doc/modules.html +0 -176
- package/doc/variables/DEFAULT_MESSAGE_ID.html +0 -104
- package/doc/variables/MAX_ID.html +0 -104
- package/doc/variables/MESSAGE_SPEC_VERSION.html +0 -104
- package/doc/variables/SYSTEM_MESSAGE_ID.html +0 -104
- package/src/client/Client.ts +0 -276
- package/src/core/MessageUtils.ts +0 -48
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Buttplug TypeScript - Remote Connector Example
|
|
2
|
+
//
|
|
3
|
+
// This example demonstrates the explicit WebSocket connector setup.
|
|
4
|
+
// While you can create a connector inline, creating it explicitly
|
|
5
|
+
// gives you more control over the connection parameters.
|
|
6
|
+
//
|
|
7
|
+
// Prerequisites:
|
|
8
|
+
// 1. Install Intiface Central: https://intiface.com/central
|
|
9
|
+
// 2. Start the server in Intiface Central
|
|
10
|
+
// 3. Run: npx ts-node --esm remote-connector-example.ts
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
ButtplugClient,
|
|
14
|
+
ButtplugNodeWebsocketClientConnector,
|
|
15
|
+
ButtplugBrowserWebsocketClientConnector,
|
|
16
|
+
} from 'buttplug';
|
|
17
|
+
import * as readline from 'readline';
|
|
18
|
+
|
|
19
|
+
async function waitForEnter(prompt: string): Promise<void> {
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout,
|
|
23
|
+
});
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
rl.question(prompt, () => {
|
|
26
|
+
rl.close();
|
|
27
|
+
resolve();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main(): Promise<void> {
|
|
33
|
+
// Method 1: Inline connector creation (most common)
|
|
34
|
+
// This is the simplest approach for most applications.
|
|
35
|
+
console.log('Method 1: Inline connector creation');
|
|
36
|
+
console.log(' const connector = new ButtplugNodeWebsocketClientConnector(url);');
|
|
37
|
+
console.log(' await client.connect(connector);');
|
|
38
|
+
console.log(' (Simple and direct)\n');
|
|
39
|
+
|
|
40
|
+
// Method 2: Explicit connector creation
|
|
41
|
+
// Use this when you need to reuse the connector or
|
|
42
|
+
// configure it before connecting.
|
|
43
|
+
console.log('Method 2: Explicit connector creation');
|
|
44
|
+
console.log(' const connector = new ButtplugNodeWebsocketClientConnector(url);');
|
|
45
|
+
console.log(' // ... configure connector if needed ...');
|
|
46
|
+
console.log(' await client.connect(connector);');
|
|
47
|
+
console.log(' (More control over connector lifecycle)\n');
|
|
48
|
+
|
|
49
|
+
// Note about environments:
|
|
50
|
+
// - Node.js: Use ButtplugNodeWebsocketClientConnector (uses 'ws' package)
|
|
51
|
+
// - Browser: Use ButtplugBrowserWebsocketClientConnector (uses native WebSocket)
|
|
52
|
+
console.log('Environment-specific connectors:');
|
|
53
|
+
console.log(' - Node.js: ButtplugNodeWebsocketClientConnector');
|
|
54
|
+
console.log(' - Browser: ButtplugBrowserWebsocketClientConnector\n');
|
|
55
|
+
|
|
56
|
+
// Let's actually connect using the explicit connector method
|
|
57
|
+
const client = new ButtplugClient('Remote Connector Example');
|
|
58
|
+
const connector = new ButtplugNodeWebsocketClientConnector(
|
|
59
|
+
'ws://127.0.0.1:12345'
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
console.log('Connecting using explicit connector...');
|
|
63
|
+
try {
|
|
64
|
+
await client.connect(connector);
|
|
65
|
+
console.log('Connected successfully!');
|
|
66
|
+
console.log(` Connected: ${client.connected}`);
|
|
67
|
+
|
|
68
|
+
await waitForEnter('\nPress Enter to disconnect...');
|
|
69
|
+
|
|
70
|
+
await client.disconnect();
|
|
71
|
+
console.log('Disconnected.');
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (e instanceof Error) {
|
|
74
|
+
console.log(`Connection failed: ${e.message}`);
|
|
75
|
+
}
|
|
76
|
+
console.log(
|
|
77
|
+
'\nMake sure Intiface Central is running with the server started.'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await waitForEnter('\nPress Enter to exit...');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "."
|
|
11
|
+
},
|
|
12
|
+
"include": ["*.ts"],
|
|
13
|
+
"exclude": ["node_modules", "dist"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Buttplug Web - Complete Application Example
|
|
2
|
+
//
|
|
3
|
+
// This is a complete, working example that demonstrates the full workflow
|
|
4
|
+
// of a Buttplug application in a browser. If you're new to Buttplug, start here!
|
|
5
|
+
//
|
|
6
|
+
// Prerequisites:
|
|
7
|
+
// 1. Install Intiface Central: https://intiface.com/central
|
|
8
|
+
// 2. Start the server in Intiface Central (click "Start Server")
|
|
9
|
+
// 3. Include Buttplug via CDN in your HTML:
|
|
10
|
+
// <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
|
|
11
|
+
// 4. Call runApplicationExample() from your page
|
|
12
|
+
|
|
13
|
+
async function runApplicationExample() {
|
|
14
|
+
console.log("===========================================");
|
|
15
|
+
console.log(" Buttplug Web Application Example");
|
|
16
|
+
console.log("===========================================\n");
|
|
17
|
+
|
|
18
|
+
// Step 1: Create a client
|
|
19
|
+
// The client name identifies your application to the server.
|
|
20
|
+
const client = new Buttplug.ButtplugClient("My Buttplug Application");
|
|
21
|
+
|
|
22
|
+
// Step 2: Set up event handlers
|
|
23
|
+
// Always do this BEFORE connecting to avoid missing events.
|
|
24
|
+
client.addListener("deviceadded", (device) => {
|
|
25
|
+
console.log(`[+] Device connected: ${device.name}`);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
client.addListener("deviceremoved", (device) => {
|
|
29
|
+
console.log(`[-] Device disconnected: ${device.name}`);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
client.addListener("disconnect", () => {
|
|
33
|
+
console.log("[!] Server connection lost!");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Step 3: Connect to the server
|
|
37
|
+
console.log("Connecting to Intiface Central...");
|
|
38
|
+
try {
|
|
39
|
+
const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector(
|
|
40
|
+
"ws://127.0.0.1:12345"
|
|
41
|
+
);
|
|
42
|
+
await client.connect(connector);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (e instanceof Buttplug.ButtplugClientConnectorException) {
|
|
45
|
+
alert(
|
|
46
|
+
"Could not connect to Intiface Central!\n\n" +
|
|
47
|
+
"Make sure Intiface Central is running and the server is started.\n" +
|
|
48
|
+
"Default address: ws://127.0.0.1:12345"
|
|
49
|
+
);
|
|
50
|
+
console.log("ERROR: Could not connect to Intiface Central!");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
throw e;
|
|
54
|
+
}
|
|
55
|
+
console.log("Connected!\n");
|
|
56
|
+
|
|
57
|
+
// Step 4: Scan for devices
|
|
58
|
+
console.log("Scanning for devices...");
|
|
59
|
+
console.log("Turn on your Bluetooth/USB devices now.\n");
|
|
60
|
+
await client.startScanning();
|
|
61
|
+
|
|
62
|
+
// Wait for devices (using alert/confirm for browser interaction)
|
|
63
|
+
alert("Scanning for devices...\n\nTurn on your devices, then click OK when ready.");
|
|
64
|
+
await client.stopScanning();
|
|
65
|
+
|
|
66
|
+
// Step 5: Check what devices we found
|
|
67
|
+
const devices = Array.from(client.devices.values());
|
|
68
|
+
if (devices.length === 0) {
|
|
69
|
+
alert(
|
|
70
|
+
"No devices found!\n\n" +
|
|
71
|
+
"Make sure your device is:\n" +
|
|
72
|
+
"- Turned on\n" +
|
|
73
|
+
"- In pairing/discoverable mode\n" +
|
|
74
|
+
"- Supported by Buttplug (check https://iostindex.com)"
|
|
75
|
+
);
|
|
76
|
+
console.log("No devices found.");
|
|
77
|
+
await client.disconnect();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`\nFound ${devices.length} device(s):\n`);
|
|
82
|
+
|
|
83
|
+
// Step 6: Display device capabilities
|
|
84
|
+
for (const device of devices) {
|
|
85
|
+
console.log(` ${device.name}`);
|
|
86
|
+
|
|
87
|
+
// Check output capabilities
|
|
88
|
+
const outputs = [];
|
|
89
|
+
if (device.hasOutput(Buttplug.OutputType.Vibrate)) outputs.push("Vibrate");
|
|
90
|
+
if (device.hasOutput(Buttplug.OutputType.Rotate)) outputs.push("Rotate");
|
|
91
|
+
if (device.hasOutput(Buttplug.OutputType.Oscillate)) outputs.push("Oscillate");
|
|
92
|
+
if (device.hasOutput(Buttplug.OutputType.Position)) outputs.push("Position");
|
|
93
|
+
if (device.hasOutput(Buttplug.OutputType.Constrict)) outputs.push("Constrict");
|
|
94
|
+
|
|
95
|
+
if (outputs.length > 0) {
|
|
96
|
+
console.log(` Outputs: ${outputs.join(", ")}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check input capabilities
|
|
100
|
+
const inputs = [];
|
|
101
|
+
if (device.hasInput(Buttplug.InputType.Battery)) inputs.push("Battery");
|
|
102
|
+
if (device.hasInput(Buttplug.InputType.RSSI)) inputs.push("RSSI");
|
|
103
|
+
|
|
104
|
+
if (inputs.length > 0) {
|
|
105
|
+
console.log(` Inputs: ${inputs.join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Step 7: Interactive device control
|
|
110
|
+
console.log("\n=== Interactive Control ===");
|
|
111
|
+
console.log("Use the prompts to control devices.");
|
|
112
|
+
|
|
113
|
+
let running = true;
|
|
114
|
+
while (running) {
|
|
115
|
+
const input = prompt(
|
|
116
|
+
"Commands:\n" +
|
|
117
|
+
" v <0-100> - Vibrate all devices at percentage\n" +
|
|
118
|
+
" s - Stop all devices\n" +
|
|
119
|
+
" b - Read battery levels\n" +
|
|
120
|
+
" q - Quit\n\n" +
|
|
121
|
+
"Enter command:"
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (input === null) {
|
|
125
|
+
// User clicked Cancel
|
|
126
|
+
running = false;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const cmd = input.trim().toLowerCase();
|
|
131
|
+
|
|
132
|
+
if (!cmd) continue;
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
if (cmd.startsWith("v ")) {
|
|
136
|
+
// Vibrate command
|
|
137
|
+
const percentStr = cmd.slice(2);
|
|
138
|
+
const percent = parseInt(percentStr, 10);
|
|
139
|
+
if (!isNaN(percent) && percent >= 0 && percent <= 100) {
|
|
140
|
+
const intensity = percent / 100.0;
|
|
141
|
+
for (const device of devices) {
|
|
142
|
+
if (device.hasOutput(Buttplug.OutputType.Vibrate)) {
|
|
143
|
+
await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(intensity));
|
|
144
|
+
console.log(` ${device.name}: vibrating at ${percent}%`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
alert("Usage: v <0-100>");
|
|
149
|
+
}
|
|
150
|
+
} else if (cmd === "s") {
|
|
151
|
+
// Stop all devices
|
|
152
|
+
await client.stopAllDevices();
|
|
153
|
+
console.log(" All devices stopped.");
|
|
154
|
+
} else if (cmd === "b") {
|
|
155
|
+
// Read battery levels
|
|
156
|
+
let batteryInfo = "Battery Levels:\n\n";
|
|
157
|
+
for (const device of devices) {
|
|
158
|
+
if (device.hasInput(Buttplug.InputType.Battery)) {
|
|
159
|
+
try {
|
|
160
|
+
const battery = await device.battery();
|
|
161
|
+
const msg = `${device.name}: ${(battery * 100).toFixed(0)}%`;
|
|
162
|
+
console.log(` ${msg}`);
|
|
163
|
+
batteryInfo += msg + "\n";
|
|
164
|
+
} catch (e) {
|
|
165
|
+
console.log(` ${device.name}: could not read battery`);
|
|
166
|
+
batteryInfo += `${device.name}: could not read battery\n`;
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
console.log(` ${device.name}: no battery sensor`);
|
|
170
|
+
batteryInfo += `${device.name}: no battery sensor\n`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
alert(batteryInfo);
|
|
174
|
+
} else if (cmd === "q") {
|
|
175
|
+
running = false;
|
|
176
|
+
} else {
|
|
177
|
+
alert("Unknown command. Use v, s, b, or q.");
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
if (e instanceof Buttplug.ButtplugDeviceError) {
|
|
181
|
+
console.log(` Device error: ${e.message}`);
|
|
182
|
+
alert(`Device error: ${e.message}`);
|
|
183
|
+
} else if (e instanceof Buttplug.ButtplugError) {
|
|
184
|
+
console.log(` Error: ${e.message}`);
|
|
185
|
+
alert(`Error: ${e.message}`);
|
|
186
|
+
} else {
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Step 8: Clean up
|
|
193
|
+
console.log("\nStopping devices and disconnecting...");
|
|
194
|
+
await client.stopAllDevices();
|
|
195
|
+
await client.disconnect();
|
|
196
|
+
console.log("Goodbye!");
|
|
197
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Buttplug Web - Async Patterns Example
|
|
2
|
+
//
|
|
3
|
+
// This example demonstrates async/await patterns and event handling
|
|
4
|
+
// in the Buttplug library. The library is fully async - all operations
|
|
5
|
+
// that might block (network, device communication) use async/await.
|
|
6
|
+
//
|
|
7
|
+
// Include Buttplug via CDN:
|
|
8
|
+
// <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
|
|
9
|
+
|
|
10
|
+
async function runAsyncExample() {
|
|
11
|
+
console.log("Running async example");
|
|
12
|
+
|
|
13
|
+
const client = new Buttplug.ButtplugClient("Async Example");
|
|
14
|
+
|
|
15
|
+
// Events in buttplug-js use EventEmitter3.
|
|
16
|
+
// You can use addListener or on to subscribe to events.
|
|
17
|
+
|
|
18
|
+
// 'deviceadded' is fired when a new device connects
|
|
19
|
+
client.addListener("deviceadded", async (device) => {
|
|
20
|
+
// Note: Event handlers can be async!
|
|
21
|
+
console.log(`[Event] Device added: ${device.name}`);
|
|
22
|
+
|
|
23
|
+
// You can interact with the device in the event handler
|
|
24
|
+
if (device.hasOutput(Buttplug.OutputType.Vibrate)) {
|
|
25
|
+
console.log(" Sending welcome vibration...");
|
|
26
|
+
await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(0.25));
|
|
27
|
+
await new Promise(r => setTimeout(r, 200));
|
|
28
|
+
await device.stop();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 'deviceremoved' is fired when a device disconnects
|
|
33
|
+
client.addListener("deviceremoved", (device) => {
|
|
34
|
+
console.log(`[Event] Device removed: ${device.name}`);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// 'scanningfinished' is fired when scanning completes
|
|
38
|
+
// (some protocols scan continuously until stopped)
|
|
39
|
+
client.addListener("scanningfinished", () => {
|
|
40
|
+
console.log("[Event] Scanning finished");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// 'disconnect' is fired when the server connection drops
|
|
44
|
+
client.addListener("disconnect", () => {
|
|
45
|
+
console.log("[Event] Server disconnected!");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// 'inputreading' is fired when subscribed sensor data arrives
|
|
49
|
+
client.addListener("inputreading", (reading) => {
|
|
50
|
+
console.log(`[Event] Input reading: ${JSON.stringify(reading)}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Connect asynchronously - this may take time due to network
|
|
54
|
+
console.log("Connecting to server...");
|
|
55
|
+
const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345");
|
|
56
|
+
await client.connect(connector);
|
|
57
|
+
console.log("Connected!");
|
|
58
|
+
|
|
59
|
+
// Scanning is also async - we start it and wait for events
|
|
60
|
+
console.log("Starting scan. Turn on devices now...");
|
|
61
|
+
console.log("(Events will be printed as devices connect)");
|
|
62
|
+
await client.startScanning();
|
|
63
|
+
|
|
64
|
+
// Demonstrate concurrent operations after 5 seconds
|
|
65
|
+
setTimeout(async () => {
|
|
66
|
+
console.log("\nDemonstrating concurrent device control...");
|
|
67
|
+
|
|
68
|
+
// Convert devices Map to array
|
|
69
|
+
const devices = Array.from(client.devices.values());
|
|
70
|
+
|
|
71
|
+
if (devices.length > 0) {
|
|
72
|
+
// Send commands to all devices concurrently
|
|
73
|
+
const tasks = devices
|
|
74
|
+
.filter((d) => d.hasOutput(Buttplug.OutputType.Vibrate))
|
|
75
|
+
.map(async (device) => {
|
|
76
|
+
console.log(` Vibrating ${device.name}...`);
|
|
77
|
+
await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(0.5));
|
|
78
|
+
await new Promise(r => setTimeout(r, 500));
|
|
79
|
+
await device.stop();
|
|
80
|
+
console.log(` ${device.name} stopped.`);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Wait for all commands to complete
|
|
84
|
+
await Promise.all(tasks);
|
|
85
|
+
console.log("All devices stopped.");
|
|
86
|
+
} else {
|
|
87
|
+
console.log("No devices connected.");
|
|
88
|
+
}
|
|
89
|
+
}, 5000);
|
|
90
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Buttplug Web - Device Control Example
|
|
2
|
+
//
|
|
3
|
+
// This example demonstrates how to send commands to devices,
|
|
4
|
+
// query device capabilities, and use the v4 command builder API.
|
|
5
|
+
//
|
|
6
|
+
// Include Buttplug via CDN:
|
|
7
|
+
// <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
|
|
8
|
+
|
|
9
|
+
async function runDeviceControlExample() {
|
|
10
|
+
const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345");
|
|
11
|
+
const client = new Buttplug.ButtplugClient("Device Control Example");
|
|
12
|
+
|
|
13
|
+
// Set up event handlers before connecting
|
|
14
|
+
client.addListener("deviceadded", async (device) => {
|
|
15
|
+
console.log(`Device connected: ${device.name}`);
|
|
16
|
+
|
|
17
|
+
// Show currently connected devices (client.devices is a Map in v4)
|
|
18
|
+
console.log("Currently connected devices:");
|
|
19
|
+
for (const [index, dev] of client.devices) {
|
|
20
|
+
console.log(` - ${dev.name} (Index: ${index})`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check if device supports vibration using v4 API
|
|
24
|
+
if (!device.hasOutput(Buttplug.OutputType.Vibrate)) {
|
|
25
|
+
console.log("Device does not support vibration, skipping control demo.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log("Device supports vibration. Sending commands...");
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Use the v4 command builder API
|
|
33
|
+
console.log("Vibrating at 100%...");
|
|
34
|
+
await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(1.0));
|
|
35
|
+
|
|
36
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
37
|
+
|
|
38
|
+
console.log("Vibrating at 50%...");
|
|
39
|
+
await device.runOutput(Buttplug.DeviceOutput.Vibrate.percent(0.5));
|
|
40
|
+
|
|
41
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
42
|
+
|
|
43
|
+
console.log("Stopping device...");
|
|
44
|
+
await device.stop();
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.log("Error sending command:", e);
|
|
47
|
+
if (e instanceof Buttplug.ButtplugDeviceError) {
|
|
48
|
+
console.log("This is a device error - device may have disconnected.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check for battery support using v4 API
|
|
53
|
+
if (device.hasInput(Buttplug.InputType.Battery)) {
|
|
54
|
+
try {
|
|
55
|
+
const level = await device.battery();
|
|
56
|
+
console.log(`${device.name} Battery Level: ${(level * 100).toFixed(0)}%`);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.log("Could not read battery level:", e);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Demonstrate other output types if available
|
|
63
|
+
if (device.hasOutput(Buttplug.OutputType.Rotate)) {
|
|
64
|
+
console.log("Device supports rotation. Rotating at 50%...");
|
|
65
|
+
await device.runOutput(Buttplug.DeviceOutput.Rotate.percent(0.5));
|
|
66
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
67
|
+
await device.stop();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (device.hasOutput(Buttplug.OutputType.Position)) {
|
|
71
|
+
console.log("Device supports position control. Moving...");
|
|
72
|
+
await device.runOutput(Buttplug.DeviceOutput.PositionWithDuration.percent(1.0, 500));
|
|
73
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
74
|
+
await device.runOutput(Buttplug.DeviceOutput.PositionWithDuration.percent(0.0, 500));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
client.addListener("deviceremoved", (device) => {
|
|
79
|
+
console.log(`Device disconnected: ${device.name}`);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
console.log("Connecting...");
|
|
83
|
+
await client.connect(connector);
|
|
84
|
+
console.log("Connected! Scanning for devices...");
|
|
85
|
+
|
|
86
|
+
await client.startScanning();
|
|
87
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Buttplug Web - Device Enumeration Example
|
|
2
|
+
//
|
|
3
|
+
// This example demonstrates how to scan for devices and handle
|
|
4
|
+
// device connection/disconnection events.
|
|
5
|
+
//
|
|
6
|
+
// Include Buttplug via CDN:
|
|
7
|
+
// <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
|
|
8
|
+
|
|
9
|
+
async function runDeviceEnumerationExample() {
|
|
10
|
+
const client = new Buttplug.ButtplugClient("Device Enumeration Example");
|
|
11
|
+
|
|
12
|
+
// Set up event handlers BEFORE connecting.
|
|
13
|
+
// This ensures we don't miss any events, including devices
|
|
14
|
+
// that are already connected to the server.
|
|
15
|
+
|
|
16
|
+
client.addListener("deviceadded", (device) => {
|
|
17
|
+
console.log(`Device connected: ${device.name}`);
|
|
18
|
+
|
|
19
|
+
// The client maintains a Map of all known devices.
|
|
20
|
+
// In v4, client.devices is a Map<number, ButtplugClientDevice>
|
|
21
|
+
console.log("Currently connected devices:");
|
|
22
|
+
for (const [index, dev] of client.devices) {
|
|
23
|
+
console.log(` - ${dev.name} (Index: ${index})`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
client.addListener("deviceremoved", (device) => {
|
|
28
|
+
console.log(`Device disconnected: ${device.name}`);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
client.addListener("scanningfinished", () => {
|
|
32
|
+
console.log("Scanning finished.");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Connect to the server (requires Intiface Central running)
|
|
36
|
+
const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://localhost:12345");
|
|
37
|
+
|
|
38
|
+
console.log("Connecting...");
|
|
39
|
+
await client.connect(connector);
|
|
40
|
+
console.log("Connected!");
|
|
41
|
+
|
|
42
|
+
// Start scanning for devices.
|
|
43
|
+
// Devices will be announced via the 'deviceadded' event.
|
|
44
|
+
console.log("Starting device scan... Turn on your devices now!");
|
|
45
|
+
await client.startScanning();
|
|
46
|
+
|
|
47
|
+
// Note: In a real application, you would call client.stopScanning()
|
|
48
|
+
// when you're done scanning, and client.disconnect() when finished.
|
|
49
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Buttplug Web - Device Info Example
|
|
2
|
+
//
|
|
3
|
+
// This example demonstrates how to introspect device features
|
|
4
|
+
// and capabilities in detail using the v4 API.
|
|
5
|
+
//
|
|
6
|
+
// Include Buttplug via CDN:
|
|
7
|
+
// <script src="https://cdn.jsdelivr.net/npm/buttplug@4.0.0/dist/web/buttplug.min.js"></script>
|
|
8
|
+
|
|
9
|
+
function printDeviceInfo(device) {
|
|
10
|
+
console.log("==================================================");
|
|
11
|
+
console.log(`Device: ${device.name}`);
|
|
12
|
+
if (device.displayName) {
|
|
13
|
+
console.log(`Display Name: ${device.displayName}`);
|
|
14
|
+
}
|
|
15
|
+
console.log(`Index: ${device.index}`);
|
|
16
|
+
if (device.messageTimingGap !== undefined) {
|
|
17
|
+
console.log(`Message Timing Gap: ${device.messageTimingGap}ms`);
|
|
18
|
+
}
|
|
19
|
+
console.log("==================================================");
|
|
20
|
+
|
|
21
|
+
// Collect output capabilities
|
|
22
|
+
const outputTypes = [];
|
|
23
|
+
if (device.hasOutput(Buttplug.OutputType.Vibrate)) outputTypes.push("Vibrate");
|
|
24
|
+
if (device.hasOutput(Buttplug.OutputType.Rotate)) outputTypes.push("Rotate");
|
|
25
|
+
if (device.hasOutput(Buttplug.OutputType.Oscillate)) outputTypes.push("Oscillate");
|
|
26
|
+
if (device.hasOutput(Buttplug.OutputType.Position)) outputTypes.push("Position");
|
|
27
|
+
if (device.hasOutput(Buttplug.OutputType.Constrict)) outputTypes.push("Constrict");
|
|
28
|
+
if (device.hasOutput(Buttplug.OutputType.Inflate)) outputTypes.push("Inflate");
|
|
29
|
+
if (device.hasOutput(Buttplug.OutputType.Temperature)) outputTypes.push("Temperature");
|
|
30
|
+
if (device.hasOutput(Buttplug.OutputType.Led)) outputTypes.push("LED");
|
|
31
|
+
|
|
32
|
+
if (outputTypes.length > 0) {
|
|
33
|
+
console.log(`\nOutput Capabilities: ${outputTypes.join(", ")}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Collect input capabilities
|
|
37
|
+
const inputTypes = [];
|
|
38
|
+
if (device.hasInput(Buttplug.InputType.Battery)) inputTypes.push("Battery");
|
|
39
|
+
if (device.hasInput(Buttplug.InputType.RSSI)) inputTypes.push("RSSI");
|
|
40
|
+
if (device.hasInput(Buttplug.InputType.Button)) inputTypes.push("Button");
|
|
41
|
+
if (device.hasInput(Buttplug.InputType.Pressure)) inputTypes.push("Pressure");
|
|
42
|
+
|
|
43
|
+
if (inputTypes.length > 0) {
|
|
44
|
+
console.log(`Input Capabilities: ${inputTypes.join(", ")}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Detailed feature breakdown
|
|
48
|
+
console.log("\nDetailed Features:");
|
|
49
|
+
for (const [index, feature] of device.features) {
|
|
50
|
+
// Access the underlying feature definition
|
|
51
|
+
const def = feature._feature;
|
|
52
|
+
console.log(`\n Feature ${index}: ${def.FeatureDescriptor}`);
|
|
53
|
+
|
|
54
|
+
if (def.Output) {
|
|
55
|
+
console.log(" Outputs:");
|
|
56
|
+
for (const [type, config] of Object.entries(def.Output)) {
|
|
57
|
+
console.log(` - ${type}: steps ${config.Value[0]}-${config.Value[1]}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (def.Input) {
|
|
62
|
+
console.log(" Inputs:");
|
|
63
|
+
for (const [type, config] of Object.entries(def.Input)) {
|
|
64
|
+
console.log(` - ${type}: commands [${config.Command.join(", ")}]`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function runDeviceInfoExample() {
|
|
71
|
+
const client = new Buttplug.ButtplugClient("Device Info Example");
|
|
72
|
+
|
|
73
|
+
// Connect to the server
|
|
74
|
+
const connector = new Buttplug.ButtplugBrowserWebsocketClientConnector("ws://127.0.0.1:12345");
|
|
75
|
+
|
|
76
|
+
console.log("Connecting...");
|
|
77
|
+
await client.connect(connector);
|
|
78
|
+
console.log("Connected! Scanning for devices...");
|
|
79
|
+
console.log("Turn on your devices now. Info will be printed as they connect.\n");
|
|
80
|
+
|
|
81
|
+
// Set up device event to print info when devices connect
|
|
82
|
+
client.addListener("deviceadded", (device) => {
|
|
83
|
+
printDeviceInfo(device);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
await client.startScanning();
|
|
87
|
+
|
|
88
|
+
// After a few seconds, also show summary of all connected devices
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
console.log("\n\n========== SUMMARY ==========");
|
|
91
|
+
if (client.devices.size === 0) {
|
|
92
|
+
console.log("No devices connected.");
|
|
93
|
+
} else {
|
|
94
|
+
console.log(`Found ${client.devices.size} device(s):`);
|
|
95
|
+
for (const [index, device] of client.devices) {
|
|
96
|
+
console.log(` ${index}: ${device.name}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}, 5000);
|
|
100
|
+
}
|