dualsense-ts 6.2.0 → 6.4.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/LINUX_HID.md +85 -0
- package/README.md +83 -12
- package/dist/dualsense.d.ts +28 -8
- package/dist/dualsense.d.ts.map +1 -1
- package/dist/dualsense.js +57 -17
- package/dist/dualsense.js.map +1 -1
- package/dist/hid/bt_checksum.d.ts +7 -0
- package/dist/hid/bt_checksum.d.ts.map +1 -1
- package/dist/hid/bt_checksum.js +33 -1
- package/dist/hid/bt_checksum.js.map +1 -1
- package/dist/hid/dualsense_hid.d.ts +77 -0
- package/dist/hid/dualsense_hid.d.ts.map +1 -1
- package/dist/hid/dualsense_hid.js +193 -0
- package/dist/hid/dualsense_hid.js.map +1 -1
- package/dist/hid/factory_info.d.ts +53 -0
- package/dist/hid/factory_info.d.ts.map +1 -0
- package/dist/hid/factory_info.js +166 -0
- package/dist/hid/factory_info.js.map +1 -0
- package/dist/hid/firmware_info.d.ts +46 -0
- package/dist/hid/firmware_info.d.ts.map +1 -0
- package/dist/hid/firmware_info.js +109 -0
- package/dist/hid/firmware_info.js.map +1 -0
- package/dist/hid/hid_provider.d.ts +12 -0
- package/dist/hid/hid_provider.d.ts.map +1 -1
- package/dist/hid/hid_provider.js +13 -0
- package/dist/hid/hid_provider.js.map +1 -1
- package/dist/hid/index.d.ts +3 -0
- package/dist/hid/index.d.ts.map +1 -1
- package/dist/hid/index.js +3 -0
- package/dist/hid/index.js.map +1 -1
- package/dist/hid/node_hid_provider.d.ts +2 -0
- package/dist/hid/node_hid_provider.d.ts.map +1 -1
- package/dist/hid/node_hid_provider.js +14 -0
- package/dist/hid/node_hid_provider.js.map +1 -1
- package/dist/hid/pairing_info.d.ts +9 -0
- package/dist/hid/pairing_info.d.ts.map +1 -0
- package/dist/hid/pairing_info.js +33 -0
- package/dist/hid/pairing_info.js.map +1 -0
- package/dist/hid/web_hid_provider.d.ts +14 -0
- package/dist/hid/web_hid_provider.d.ts.map +1 -1
- package/dist/hid/web_hid_provider.js +79 -8
- package/dist/hid/web_hid_provider.js.map +1 -1
- package/dist/id.d.ts +4 -0
- package/dist/id.d.ts.map +1 -1
- package/dist/manager.d.ts +57 -4
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +248 -66
- package/dist/manager.js.map +1 -1
- package/nodehid_example/debug.ts +43 -13
- package/nodehid_example/single.ts +29 -0
- package/package.json +1 -1
- package/src/dualsense.ts +73 -23
- package/src/hid/bt_checksum.ts +39 -0
- package/src/hid/dualsense_hid.ts +230 -0
- package/src/hid/factory_info.ts +206 -0
- package/src/hid/firmware_info.ts +157 -0
- package/src/hid/hid_provider.ts +22 -0
- package/src/hid/index.ts +3 -0
- package/src/hid/node_hid_provider.ts +14 -0
- package/src/hid/pairing_info.ts +33 -0
- package/src/hid/web_hid_provider.ts +87 -8
- package/src/id.ts +5 -0
- package/src/manager.ts +285 -71
- package/webhid_example/build/asset-manifest.json +3 -3
- package/webhid_example/build/index.html +1 -1
- package/webhid_example/build/static/js/main.1c1a2c23.js +3 -0
- package/webhid_example/build/static/js/main.1c1a2c23.js.map +1 -0
- package/webhid_example/src/App.tsx +7 -1
- package/webhid_example/src/hud/AudioIndicator.tsx +116 -0
- package/webhid_example/src/hud/BatteryIndicator.tsx +4 -2
- package/webhid_example/src/hud/ColorIndicator.tsx +72 -0
- package/webhid_example/src/hud/ControllerConnection.tsx +29 -2
- package/webhid_example/src/hud/Debugger.tsx +31 -1
- package/webhid_example/src/hud/LightbarFadeButtons.tsx +2 -2
- package/webhid_example/src/hud/MuteLedControls.tsx +3 -2
- package/webhid_example/src/hud/index.tsx +2 -0
- package/webhid_example/build/static/js/main.2ac31d24.js +0 -3
- package/webhid_example/build/static/js/main.2ac31d24.js.map +0 -1
- /package/webhid_example/build/static/js/{main.2ac31d24.js.LICENSE.txt → main.1c1a2c23.js.LICENSE.txt} +0 -0
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
BatteryIndicator,
|
|
10
10
|
MuteLedControls,
|
|
11
11
|
} from "./hud";
|
|
12
|
+
import { AudioIndicator } from "./hud/AudioIndicator";
|
|
13
|
+
import { ColorIndicator } from "./hud/ColorIndicator";
|
|
12
14
|
import { Debugger } from "./hud/Debugger";
|
|
13
15
|
import { RightStick } from "./hud/RightStick";
|
|
14
16
|
import { LeftShoulder, RightShoulder } from "./hud/ShoulderVisualization";
|
|
@@ -394,6 +396,7 @@ function useManagerState() {
|
|
|
394
396
|
const [activeCount, setActiveCount] = React.useState(
|
|
395
397
|
manager?.state.active ?? 0,
|
|
396
398
|
);
|
|
399
|
+
const [pending, setPending] = React.useState(manager?.pending ?? false);
|
|
397
400
|
|
|
398
401
|
React.useEffect(() => {
|
|
399
402
|
const m = manager;
|
|
@@ -401,13 +404,14 @@ function useManagerState() {
|
|
|
401
404
|
const update = () => {
|
|
402
405
|
setControllers([...m.controllers]);
|
|
403
406
|
setActiveCount(m.state.active);
|
|
407
|
+
setPending(m.pending);
|
|
404
408
|
};
|
|
405
409
|
m.on("change", update);
|
|
406
410
|
const interval = setInterval(update, 500);
|
|
407
411
|
return () => clearInterval(interval);
|
|
408
412
|
}, []);
|
|
409
413
|
|
|
410
|
-
return { controllers, activeCount };
|
|
414
|
+
return { controllers, activeCount, pending };
|
|
411
415
|
}
|
|
412
416
|
|
|
413
417
|
export const App = () => {
|
|
@@ -505,6 +509,8 @@ export const App = () => {
|
|
|
505
509
|
<ControllerConnection />
|
|
506
510
|
<BatteryIndicator />
|
|
507
511
|
<MuteLedControls />
|
|
512
|
+
<AudioIndicator />
|
|
513
|
+
<ColorIndicator />
|
|
508
514
|
<LightbarFadeButtons />
|
|
509
515
|
{connected && (
|
|
510
516
|
<>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useContext, useEffect, useState } from "react";
|
|
2
|
+
import { Tag } from "@blueprintjs/core";
|
|
3
|
+
|
|
4
|
+
import { ControllerContext } from "../Controller";
|
|
5
|
+
|
|
6
|
+
export const AudioIndicator = () => {
|
|
7
|
+
const controller = useContext(ControllerContext);
|
|
8
|
+
const [mic, setMic] = useState(controller.microphone.state);
|
|
9
|
+
const [headphone, setHeadphone] = useState(controller.headphone.state);
|
|
10
|
+
const [connected, setConnected] = useState(controller.connection.state);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setMic(controller.microphone.state);
|
|
14
|
+
setHeadphone(controller.headphone.state);
|
|
15
|
+
setConnected(controller.connection.state);
|
|
16
|
+
controller.microphone.on("change", ({ state }) => setMic(state));
|
|
17
|
+
controller.headphone.on("change", ({ state }) => setHeadphone(state));
|
|
18
|
+
controller.connection.on("change", ({ state }) => setConnected(state));
|
|
19
|
+
}, [controller]);
|
|
20
|
+
|
|
21
|
+
if (!connected) return null;
|
|
22
|
+
if (!mic && !headphone) return null;
|
|
23
|
+
|
|
24
|
+
let label: string;
|
|
25
|
+
if (mic && headphone) {
|
|
26
|
+
label = "Headset";
|
|
27
|
+
} else if (headphone) {
|
|
28
|
+
label = "Headphones";
|
|
29
|
+
} else {
|
|
30
|
+
label = "Mic";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const icon = (
|
|
34
|
+
<svg
|
|
35
|
+
width="14"
|
|
36
|
+
height="14"
|
|
37
|
+
viewBox="0 0 14 14"
|
|
38
|
+
fill="currentColor"
|
|
39
|
+
style={{ display: "block" }}
|
|
40
|
+
>
|
|
41
|
+
{headphone ? (
|
|
42
|
+
<>
|
|
43
|
+
{/* Headphone band */}
|
|
44
|
+
<path
|
|
45
|
+
d="M2 8 Q2 2 7 2 Q12 2 12 8"
|
|
46
|
+
fill="none"
|
|
47
|
+
stroke="currentColor"
|
|
48
|
+
strokeWidth="1.2"
|
|
49
|
+
strokeLinecap="round"
|
|
50
|
+
/>
|
|
51
|
+
{/* Left ear cup */}
|
|
52
|
+
<rect x="1" y="7.5" width="2.5" height="4" rx="1" />
|
|
53
|
+
{/* Right ear cup */}
|
|
54
|
+
<rect x="10.5" y="7.5" width="2.5" height="4" rx="1" />
|
|
55
|
+
{/* Mic boom (only when mic is also connected) */}
|
|
56
|
+
{mic && (
|
|
57
|
+
<>
|
|
58
|
+
<line
|
|
59
|
+
x1="3"
|
|
60
|
+
y1="11"
|
|
61
|
+
x2="5"
|
|
62
|
+
y2="13"
|
|
63
|
+
stroke="currentColor"
|
|
64
|
+
strokeWidth="1.2"
|
|
65
|
+
strokeLinecap="round"
|
|
66
|
+
/>
|
|
67
|
+
<circle cx="5.5" cy="13" r="1" />
|
|
68
|
+
</>
|
|
69
|
+
)}
|
|
70
|
+
</>
|
|
71
|
+
) : (
|
|
72
|
+
<>
|
|
73
|
+
{/* Standalone microphone */}
|
|
74
|
+
<rect x="4.5" y="1" width="5" height="7" rx="2.5" />
|
|
75
|
+
<path
|
|
76
|
+
d="M2.5 6.5 Q2.5 11 7 11 Q11.5 11 11.5 6.5"
|
|
77
|
+
fill="none"
|
|
78
|
+
stroke="currentColor"
|
|
79
|
+
strokeWidth="1.2"
|
|
80
|
+
strokeLinecap="round"
|
|
81
|
+
/>
|
|
82
|
+
<line
|
|
83
|
+
x1="7"
|
|
84
|
+
y1="11"
|
|
85
|
+
x2="7"
|
|
86
|
+
y2="13"
|
|
87
|
+
stroke="currentColor"
|
|
88
|
+
strokeWidth="1.2"
|
|
89
|
+
strokeLinecap="round"
|
|
90
|
+
/>
|
|
91
|
+
<line
|
|
92
|
+
x1="5"
|
|
93
|
+
y1="13"
|
|
94
|
+
x2="9"
|
|
95
|
+
y2="13"
|
|
96
|
+
stroke="currentColor"
|
|
97
|
+
strokeWidth="1.2"
|
|
98
|
+
strokeLinecap="round"
|
|
99
|
+
/>
|
|
100
|
+
</>
|
|
101
|
+
)}
|
|
102
|
+
</svg>
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Tag minimal={true} intent="none" icon={icon} title={
|
|
107
|
+
mic && headphone
|
|
108
|
+
? "Headset with microphone connected"
|
|
109
|
+
: headphone
|
|
110
|
+
? "Headphones connected (no microphone)"
|
|
111
|
+
: "Microphone connected (no headphones)"
|
|
112
|
+
}>
|
|
113
|
+
{label}
|
|
114
|
+
</Tag>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
@@ -47,11 +47,13 @@ export const BatteryIndicator = () => {
|
|
|
47
47
|
const [connected, setConnected] = useState(controller.connection.state);
|
|
48
48
|
|
|
49
49
|
useEffect(() => {
|
|
50
|
+
setLevel(controller.battery.level.state);
|
|
51
|
+
setStatus(controller.battery.status.state);
|
|
52
|
+
setConnected(controller.connection.state);
|
|
50
53
|
controller.battery.level.on("change", ({ state }) => setLevel(state));
|
|
51
54
|
controller.battery.status.on("change", ({ state }) => setStatus(state));
|
|
52
55
|
controller.connection.on("change", ({ state }) => setConnected(state));
|
|
53
|
-
|
|
54
|
-
}, []);
|
|
56
|
+
}, [controller]);
|
|
55
57
|
|
|
56
58
|
if (!connected) return null;
|
|
57
59
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useContext, useEffect, useState } from "react";
|
|
2
|
+
import { Tag } from "@blueprintjs/core";
|
|
3
|
+
import styled from "styled-components";
|
|
4
|
+
import type { FactoryInfo } from "dualsense-ts";
|
|
5
|
+
|
|
6
|
+
import { ControllerContext } from "../Controller";
|
|
7
|
+
|
|
8
|
+
/** Approximate CSS colors for known DualSense body colors */
|
|
9
|
+
const colorCss: Record<string, string> = {
|
|
10
|
+
"00": "#e8e8e8",
|
|
11
|
+
"01": "#1a1a2e",
|
|
12
|
+
"02": "#c8102e",
|
|
13
|
+
"03": "#f2a6c0",
|
|
14
|
+
"04": "#6b3fa0",
|
|
15
|
+
"05": "#5b9bd5",
|
|
16
|
+
"06": "#8a9a7b",
|
|
17
|
+
"07": "#9b2335",
|
|
18
|
+
"08": "#c0c0c0",
|
|
19
|
+
"09": "#1e3a5f",
|
|
20
|
+
"10": "#2db5a0",
|
|
21
|
+
"11": "#3d4f7c",
|
|
22
|
+
"12": "#e8dfd0",
|
|
23
|
+
"30": "#4a4a4a",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const ColorDot = styled.span<{ $color: string }>`
|
|
27
|
+
display: inline-block;
|
|
28
|
+
width: 10px;
|
|
29
|
+
height: 10px;
|
|
30
|
+
border-radius: 50%;
|
|
31
|
+
background: ${(p) => p.$color};
|
|
32
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
export const ColorIndicator = () => {
|
|
37
|
+
const controller = useContext(ControllerContext);
|
|
38
|
+
const [factory, setFactory] = useState<FactoryInfo | undefined>(
|
|
39
|
+
controller.factoryInfo
|
|
40
|
+
);
|
|
41
|
+
const [connected, setConnected] = useState(controller.connection.state);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
setConnected(controller.connection.state);
|
|
45
|
+
setFactory(controller.factoryInfo);
|
|
46
|
+
controller.on("change", (c) => {
|
|
47
|
+
if (c.factoryInfo) {
|
|
48
|
+
setFactory(c.factoryInfo);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
controller.connection.on("change", ({ state }) => {
|
|
52
|
+
setConnected(state);
|
|
53
|
+
if (!state) setFactory(undefined);
|
|
54
|
+
});
|
|
55
|
+
}, [controller]);
|
|
56
|
+
|
|
57
|
+
if (!connected || !factory) return null;
|
|
58
|
+
|
|
59
|
+
const css = colorCss[factory.colorCode];
|
|
60
|
+
const label = factory.colorName ?? factory.colorCode;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Tag
|
|
64
|
+
minimal={true}
|
|
65
|
+
intent="none"
|
|
66
|
+
icon={css ? <ColorDot $color={css} /> : undefined}
|
|
67
|
+
title={`Controller color: ${label}${factory.boardRevision ? ` (${factory.boardRevision})` : ""}`}
|
|
68
|
+
>
|
|
69
|
+
{label}
|
|
70
|
+
</Tag>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEffect, useState, useContext } from "react";
|
|
2
|
-
import { Button as BlueprintButton, Tag } from "@blueprintjs/core";
|
|
2
|
+
import { Button as BlueprintButton, Tag, Spinner } from "@blueprintjs/core";
|
|
3
3
|
import styled, { keyframes } from "styled-components";
|
|
4
4
|
|
|
5
|
-
import { ControllerContext, requestPermission } from "../Controller";
|
|
5
|
+
import { ControllerContext, ManagerContext, requestPermission } from "../Controller";
|
|
6
6
|
|
|
7
7
|
const StatusContainer = styled.div`
|
|
8
8
|
display: flex;
|
|
@@ -21,14 +21,41 @@ const PulsingButton = styled(BlueprintButton)`
|
|
|
21
21
|
|
|
22
22
|
export const ControllerConnection = () => {
|
|
23
23
|
const controller = useContext(ControllerContext);
|
|
24
|
+
const manager = useContext(ManagerContext);
|
|
24
25
|
const [connected, setConnected] = useState(controller.connection.state);
|
|
26
|
+
const [pending, setPending] = useState(manager?.pending ?? false);
|
|
25
27
|
|
|
26
28
|
useEffect(() => {
|
|
29
|
+
// Sync immediately — the controller may already be connected when the
|
|
30
|
+
// context switches (e.g. after a provisional slot promotes).
|
|
31
|
+
setConnected(controller.connection.state);
|
|
27
32
|
const handler = ({ state }: { state: boolean }) => setConnected(state);
|
|
28
33
|
controller.connection.on("change", handler);
|
|
29
34
|
}, [controller]);
|
|
30
35
|
|
|
36
|
+
// The manager doesn't expose a typed event for `pending` flips, so we
|
|
37
|
+
// poll its state alongside the existing 500ms App-level poll.
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!manager) return;
|
|
40
|
+
const tick = () => setPending(manager.pending);
|
|
41
|
+
tick();
|
|
42
|
+
const interval = setInterval(tick, 250);
|
|
43
|
+
return () => clearInterval(interval);
|
|
44
|
+
}, [manager]);
|
|
45
|
+
|
|
31
46
|
if (!connected) {
|
|
47
|
+
// A controller has been opened but firmware/identity is still loading —
|
|
48
|
+
// show a spinner instead of the "Connect" button so we don't ask the
|
|
49
|
+
// user to take action on a controller that is already wired up.
|
|
50
|
+
if (pending) {
|
|
51
|
+
return (
|
|
52
|
+
<StatusContainer>
|
|
53
|
+
<Tag minimal={true} intent="warning" icon={<Spinner size={12} />}>
|
|
54
|
+
Connecting...
|
|
55
|
+
</Tag>
|
|
56
|
+
</StatusContainer>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
32
59
|
return (
|
|
33
60
|
<StatusContainer>
|
|
34
61
|
<PulsingButton
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import styled from "styled-components";
|
|
3
3
|
import { Card, Switch } from "@blueprintjs/core";
|
|
4
|
-
import { DualsenseHIDState } from "dualsense-ts";
|
|
4
|
+
import { DualsenseHIDState, FirmwareInfo, FactoryInfo, formatFirmwareVersion } from "dualsense-ts";
|
|
5
5
|
|
|
6
6
|
import { ControllerContext } from "../Controller";
|
|
7
7
|
import { TriggerEffectControls } from "./TriggerEffectControls";
|
|
@@ -27,10 +27,22 @@ export const Debugger = ({ panel }: DebuggerProps) => {
|
|
|
27
27
|
|
|
28
28
|
const [showReport, setShowReport] = React.useState<boolean>(false);
|
|
29
29
|
const [showState, setShowState] = React.useState<boolean>(false);
|
|
30
|
+
const [firmware, setFirmware] = React.useState<FirmwareInfo | undefined>(
|
|
31
|
+
controller.firmwareInfo
|
|
32
|
+
);
|
|
33
|
+
const [factory, setFactory] = React.useState<FactoryInfo | undefined>(
|
|
34
|
+
controller.factoryInfo
|
|
35
|
+
);
|
|
30
36
|
|
|
31
37
|
React.useEffect(() => {
|
|
32
38
|
controller.on("change", (controller) => {
|
|
33
39
|
setDebugState(controller.hid.state);
|
|
40
|
+
if (!firmware && controller.firmwareInfo) {
|
|
41
|
+
setFirmware(controller.firmwareInfo);
|
|
42
|
+
}
|
|
43
|
+
if (!factory && controller.factoryInfo) {
|
|
44
|
+
setFactory(controller.factoryInfo);
|
|
45
|
+
}
|
|
34
46
|
});
|
|
35
47
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
36
48
|
}, []);
|
|
@@ -54,6 +66,24 @@ export const Debugger = ({ panel }: DebuggerProps) => {
|
|
|
54
66
|
|
|
55
67
|
return (
|
|
56
68
|
<>
|
|
69
|
+
{firmware && (
|
|
70
|
+
<Card compact={true}>
|
|
71
|
+
<p style={{ fontSize: 12, opacity: 0.7, margin: 0 }}>
|
|
72
|
+
Firmware: v{formatFirmwareVersion(firmware.mainFirmwareVersion)}
|
|
73
|
+
{" · "}HW: {firmware.hardwareInfo}
|
|
74
|
+
{" · "}DSP: {firmware.dspFirmwareVersion}
|
|
75
|
+
{" · "}SBL: v{formatFirmwareVersion(firmware.sblFirmwareVersion)}
|
|
76
|
+
{" · "}Built: {firmware.buildDate} {firmware.buildTime}
|
|
77
|
+
</p>
|
|
78
|
+
{factory && (
|
|
79
|
+
<p style={{ fontSize: 12, opacity: 0.7, margin: "4px 0 0" }}>
|
|
80
|
+
Color: {factory.colorName ?? factory.colorCode}
|
|
81
|
+
{" · "}{factory.boardRevision ?? "Unknown board"}
|
|
82
|
+
{" · "}Serial: {factory.serialNumber}
|
|
83
|
+
</p>
|
|
84
|
+
)}
|
|
85
|
+
</Card>
|
|
86
|
+
)}
|
|
57
87
|
<Card compact={true}>
|
|
58
88
|
<Switch
|
|
59
89
|
label="Input State"
|
|
@@ -40,9 +40,9 @@ export const LightbarFadeButtons = () => {
|
|
|
40
40
|
const [connected, setConnected] = React.useState(controller.connection.state);
|
|
41
41
|
|
|
42
42
|
React.useEffect(() => {
|
|
43
|
+
setConnected(controller.connection.state);
|
|
43
44
|
controller.connection.on("change", ({ state }) => setConnected(state));
|
|
44
|
-
|
|
45
|
-
}, []);
|
|
45
|
+
}, [controller]);
|
|
46
46
|
|
|
47
47
|
if (!connected) return null;
|
|
48
48
|
|
|
@@ -9,10 +9,11 @@ export const MuteLedControls = () => {
|
|
|
9
9
|
const [connected, setConnected] = useState(controller.connection.state);
|
|
10
10
|
|
|
11
11
|
useEffect(() => {
|
|
12
|
+
setLedOn(controller.mute.status.state);
|
|
13
|
+
setConnected(controller.connection.state);
|
|
12
14
|
controller.mute.status.on("change", ({ state }) => setLedOn(state));
|
|
13
15
|
controller.connection.on("change", ({ state }) => setConnected(state));
|
|
14
|
-
|
|
15
|
-
}, []);
|
|
16
|
+
}, [controller]);
|
|
16
17
|
|
|
17
18
|
if (!connected) return null;
|
|
18
19
|
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* @file Automatically generated by barrelsby.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
export * from "./AudioIndicator";
|
|
5
6
|
export * from "./BatteryIndicator";
|
|
6
7
|
export * from "./BumperVisualization";
|
|
8
|
+
export * from "./ColorIndicator";
|
|
7
9
|
export * from "./ControllerConnection";
|
|
8
10
|
export * from "./Debugger";
|
|
9
11
|
export * from "./DpadVisualization";
|