From c819ad65a6ec17efa1113a16882cf8256ea1aaed Mon Sep 17 00:00:00 2001 From: ReborN Date: Thu, 4 May 2023 12:43:06 +0100 Subject: [PATCH 1/2] Split into separate file & removed custom log of button inputs. --- app/react/components/ControllerInfo.js | 175 +++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 app/react/components/ControllerInfo.js diff --git a/app/react/components/ControllerInfo.js b/app/react/components/ControllerInfo.js new file mode 100644 index 0000000..611757d --- /dev/null +++ b/app/react/components/ControllerInfo.js @@ -0,0 +1,175 @@ +import React, {useState, useEffect, useRef} from 'react'; +import {Segment, Grid, List, Checkbox} from 'semantic-ui-react'; +import AxisInfo from "./AxisInfo"; +import ButtonInfo from "./ButtonInfo"; + +// displays information about a specific gamepad +const ControllerInfo = ({ gamepad }) => { + const [buttons, setButtons] = useState([]); + const [axes, setAxes] = useState([]); + const [deadzoneEnabled, setDeadzoneEnabled] = useState(false); + const [deadzoneValue, setDeadzoneValue] = useState(0.15); + const [buttonNames, setButtonNames] = useState( + Array(gamepad?.buttons.length).fill("") + ); + const buttonCache = useRef({}); + const axisCache = useRef({}); + + const processGamepadData = () => { + // console.log("processGamepadData called"); + if (!gamepad) return; + + let buttonChanged = false; + + // Process buttons + gamepad.buttons.forEach((button, index) => { + // console.log(`Button ${index}: current value: ${button.value}, cached value: ${buttonCache.current[index]}`); + if (buttonCache.current[index] !== button.value) { + buttonChanged = true; + buttonCache.current[index] = button.value; + } + }); + + // Process axes (same logic as for buttons) + let axisChanged = false; + + gamepad.axes.forEach((axis, index) => { + const axisValue = deadzoneEnabled && Math.abs(axis) < deadzoneValue ? 0 : axis; + // console.log(`Axis ${index}: current value: ${axisValue}, cached value: ${axisCache.current[index]}`); + + if (axisCache.current[index] !== axisValue) { + axisChanged = true; + axisCache.current[index] = axisValue; + } + }); + }; + + const handleRenameButtonClick = (index, newName) => { + setButtonNames((prevButtonNames) => { + const newButtonNames = [...prevButtonNames]; + newButtonNames[index] = newName; + return newButtonNames; + }); + }; + + const handleDeadzoneToggle = () => { + setDeadzoneEnabled(!deadzoneEnabled); + }; + + const handleDeadzoneValueChange = (event) => { + const newValue = parseFloat(event.target.value); + if (newValue >= 0 && newValue <= 1) { + setDeadzoneValue(newValue); + } + }; + + // useEffect hook used to update the buttons and axes state variables + useEffect(() => { + // checks if there is a gamepad connected before updating state variables + if (!gamepad) return; + + setButtons([...gamepad.buttons]); + setAxes( + gamepad.axes.map((axis) => + deadzoneEnabled && Math.abs(axis) < deadzoneValue ? 0 : axis + ) + ); + processGamepadData(); + }, [gamepad, deadzoneEnabled, deadzoneValue]); + + // displays message if no gamepad is connected + if (!gamepad) { + return ( + +

Press a button or move an analog stick to connect the controller.

+
+ ); + } + + // displays information about buttons, axis and other misc + return ( + + + + + + +

Index

+

{gamepad.index}

+
+
+ + +

Connected

+

{gamepad.connected ? 'Yes' : 'No'}

+
+
+ + +

Timestamp

+

{gamepad.timestamp.toFixed(5)}

+
+
+
+
+
+ + +

Buttons

+ + { + buttons.map((button, index) => ( + + handleRenameButtonClick(index, newName)} + /> + + )) + } + +
+
+ + +

Axes

+ + { + axes.map((axis, index) => ( + + + + )) + } + +
+
+ + + + + + + + +
+ ); +}; + +export default ControllerInfo; From 5ae84d94ff7c04664fd0f8757c65c4e575078108 Mon Sep 17 00:00:00 2001 From: ReborN Date: Thu, 4 May 2023 12:43:58 +0100 Subject: [PATCH 2/2] Split components into separate files. --- app/react/components/AxisInfo.js | 24 +++ app/react/components/ButtonInfo.js | 36 ++++ app/react/components/ControllerTabs.js | 20 ++ app/react/components/GamepadTester.js | 278 +------------------------ app/react/components/LogContainer.js | 17 ++ app/react/components/StatusBar.js | 12 ++ 6 files changed, 113 insertions(+), 274 deletions(-) create mode 100644 app/react/components/AxisInfo.js create mode 100644 app/react/components/ButtonInfo.js create mode 100644 app/react/components/ControllerTabs.js create mode 100644 app/react/components/LogContainer.js create mode 100644 app/react/components/StatusBar.js diff --git a/app/react/components/AxisInfo.js b/app/react/components/AxisInfo.js new file mode 100644 index 0000000..3aa131a --- /dev/null +++ b/app/react/components/AxisInfo.js @@ -0,0 +1,24 @@ +import {Segment} from "semantic-ui-react"; +import React from "react"; + +const AxisInfo = ({axisValue, index}) => { + return ( + + Axis {index}: {axisValue.toFixed(2)} +
= 0 ? `${axisValue * 50}%` : '0%' + }} + >
+
+
+ ); +}; + +export default AxisInfo; diff --git a/app/react/components/ButtonInfo.js b/app/react/components/ButtonInfo.js new file mode 100644 index 0000000..2891789 --- /dev/null +++ b/app/react/components/ButtonInfo.js @@ -0,0 +1,36 @@ +import {Input, Popup, Segment} from "semantic-ui-react"; +import React from "react"; + +const ButtonInfo = ({button, buttonName, onRenameButtonClick}) => { + return ( + + {buttonName}: {button.value.toFixed(2)} +
+ + } + on="click" + hideOnScroll + position="top center" + content={ +
+ { + if (e.key === "Enter") { + onRenameButtonClick(e.target.value); + } + }} + /> +
+ } + /> + ); +}; + +export default ButtonInfo; diff --git a/app/react/components/ControllerTabs.js b/app/react/components/ControllerTabs.js new file mode 100644 index 0000000..982d6ca --- /dev/null +++ b/app/react/components/ControllerTabs.js @@ -0,0 +1,20 @@ +import {Menu} from "semantic-ui-react"; +import React from "react"; + +const ControllerTabs = ({panes, activeIndex, setActiveIndex}) => { + return ( + + {panes.map((pane, index) => ( + setActiveIndex(index)} + > + {pane.truncatedTabName} + + ))} + + ); +}; + +export default ControllerTabs; diff --git a/app/react/components/GamepadTester.js b/app/react/components/GamepadTester.js index 13fbddc..e3e9417 100644 --- a/app/react/components/GamepadTester.js +++ b/app/react/components/GamepadTester.js @@ -1,5 +1,8 @@ import React, {useState, useEffect, useRef, useCallback, useMemo} from 'react'; -import {Menu, Segment, Grid, List, Checkbox, Popup, Input} from 'semantic-ui-react'; +import ControllerInfo from "./ControllerInfo"; +import StatusBar from "./StatusBar"; +import LogContainer from "./LogContainer"; +import ControllerTabs from "./ControllerTabs"; const GamepadTester = () => { const [gamepads, setGamepads] = useState(Array(4).fill(null)); @@ -108,277 +111,4 @@ const GamepadTester = () => { ); }; -// displays information about a specific gamepad -const ControllerInfo = ({ gamepad, addToLog }) => { - const [buttons, setButtons] = useState([]); - const [axes, setAxes] = useState([]); - const [deadzoneEnabled, setDeadzoneEnabled] = useState(false); - const [deadzoneValue, setDeadzoneValue] = useState(0.15); - const [buttonNames, setButtonNames] = useState( - Array(gamepad?.buttons.length).fill("") - ); - const buttonCache = useRef({}); - const axisCache = useRef({}); - - const processGamepadData = () => { - // console.log("processGamepadData called"); - if (!gamepad) return; - - let buttonChanged = false; - - // Process buttons - gamepad.buttons.forEach((button, index) => { - // console.log(`Button ${index}: current value: ${button.value}, cached value: ${buttonCache.current[index]}`); - if (buttonCache.current[index] !== button.value) { - buttonChanged = true; - addToLog(`[input] button bt${index} changed to ${button.value}`); - buttonCache.current[index] = button.value; - } - }); - - if (buttonChanged) { - gamepad.buttons.forEach((button, index) => { - addToLog(`[input] button bt${index} state: ${button.value}`); - }); - } - - // Process axes (same logic as for buttons) - let axisChanged = false; - - gamepad.axes.forEach((axis, index) => { - const axisValue = deadzoneEnabled && Math.abs(axis) < deadzoneValue ? 0 : axis; - // console.log(`Axis ${index}: current value: ${axisValue}, cached value: ${axisCache.current[index]}`); - - if (axisCache.current[index] !== axisValue) { - axisChanged = true; - addToLog(`[input] axis ax${index} changed to ${axisValue}`); - axisCache.current[index] = axisValue; - } - }); - - if (axisChanged) { - gamepad.axes.forEach((axis, index) => { - const axisValue = deadzoneEnabled && Math.abs(axis) < deadzoneValue ? 0 : axis; - addToLog(`[input] axis ax${index} state: ${axisValue}`); - }); - } - }; - - const handleRenameButtonClick = (index, newName) => { - setButtonNames((prevButtonNames) => { - const newButtonNames = [...prevButtonNames]; - newButtonNames[index] = newName; - return newButtonNames; - }); - }; - - const handleDeadzoneToggle = () => { - setDeadzoneEnabled(!deadzoneEnabled); - }; - - const handleDeadzoneValueChange = (event) => { - const newValue = parseFloat(event.target.value); - if (newValue >= 0 && newValue <= 1) { - setDeadzoneValue(newValue); - } - }; - - // useEffect hook used to update the buttons and axes state variables - useEffect(() => { - // checks if there is a gamepad connected before updating state variables - if (!gamepad) return; - - setButtons([...gamepad.buttons]); - setAxes( - gamepad.axes.map((axis) => - deadzoneEnabled && Math.abs(axis) < deadzoneValue ? 0 : axis - ) - ); - processGamepadData(); - }, [gamepad, deadzoneEnabled, deadzoneValue]); - - // displays message if no gamepad is connected - if (!gamepad) { - return ( - -

Press a button or move an analog stick to connect the controller.

-
- ); - } - - // displays information about buttons, axis and other misc - return ( - - - - - - -

Index

-

{gamepad.index}

-
-
- - -

Connected

-

{gamepad.connected ? 'Yes' : 'No'}

-
-
- - -

Timestamp

-

{gamepad.timestamp.toFixed(5)}

-
-
-
-
-
- - -

Buttons

- - { - buttons.map((button, index) => ( - - handleRenameButtonClick(index, newName)} - /> - - )) - } - -
-
- - -

Axes

- - { - axes.map((axis, index) => ( - - - - )) - } - -
-
- - - - - - - - -
- ); -}; - -const ControllerTabs = ({panes, activeIndex, setActiveIndex}) => { - return ( - - {panes.map((pane, index) => ( - setActiveIndex(index)} - > - {pane.truncatedTabName} - - ))} - - ); -}; - -const LogContainer = ({logMessages, anyControllerConnected, hasConnectedOnce}) => { - return ( - - {logMessages.map((message, index) => { - if (index === 0 && (anyControllerConnected || hasConnectedOnce)) { - return null; - } - return

{message}

; - })} -
- ); -}; - -const StatusBar = ({connectedControllers}) => { - return ( - - Connected controllers: {connectedControllers} - - ); -}; - -const ButtonInfo = ({button, buttonName, onRenameButtonClick}) => { - return ( - - {buttonName}: {button.value.toFixed(2)} -
- - } - on="click" - hideOnScroll - position="top center" - content={ -
- { - if (e.key === "Enter") { - onRenameButtonClick(e.target.value); - } - }} - /> -
- } - /> - ); -}; - -const AxisInfo = ({axisValue, index}) => { - return ( - - Axis {index}: {axisValue.toFixed(2)} -
= 0 ? `${axisValue * 50}%` : '0%' - }} - >
-
-
- ); -}; - export default GamepadTester; diff --git a/app/react/components/LogContainer.js b/app/react/components/LogContainer.js new file mode 100644 index 0000000..410cab6 --- /dev/null +++ b/app/react/components/LogContainer.js @@ -0,0 +1,17 @@ +import {Segment} from "semantic-ui-react"; +import React from "react"; + +const LogContainer = ({logMessages, anyControllerConnected, hasConnectedOnce}) => { + return ( + + {logMessages.map((message, index) => { + if (index === 0 && (anyControllerConnected || hasConnectedOnce)) { + return null; + } + return

{message}

; + })} +
+ ); +}; + +export default LogContainer; diff --git a/app/react/components/StatusBar.js b/app/react/components/StatusBar.js new file mode 100644 index 0000000..e3d187b --- /dev/null +++ b/app/react/components/StatusBar.js @@ -0,0 +1,12 @@ +import {Segment} from "semantic-ui-react"; +import React from "react"; + +const StatusBar = ({connectedControllers}) => { + return ( + + Connected controllers: {connectedControllers} + + ); +}; + +export default StatusBar;