From 11e10caa32b6113d3efd299dc49aa07e599457c7 Mon Sep 17 00:00:00 2001 From: maxminoS <11131914+maxminoS@users.noreply.github.com> Date: Fri, 14 May 2021 20:52:29 +0700 Subject: [PATCH] Clean up and optimize codebase with more readable code (#36) * Fix Go startup in README (#35) * Replace mouse button state logic with useReducer and useContext * Optimized tap interval * Clean up type declarations * Disable other Touchpad gestures in Android --- README.md | 2 +- client/App.tsx | 54 ++++------------------ client/components/ConnectModal.tsx | 2 +- client/components/MouseClick.tsx | 27 +++++------ client/components/Touchpad.tsx | 31 +++++++------ client/contexts/LongButtonContext.tsx | 64 +++++++++++++++++++++++++++ client/tsconfig.json | 2 + client/utils.ts | 27 ++++++----- 8 files changed, 119 insertions(+), 90 deletions(-) create mode 100644 client/contexts/LongButtonContext.tsx diff --git a/README.md b/README.md index 35c07c8..612b8dc 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Run the Go server in the device you want to be controlled by going to `server/` ## Usage -The frontend can send signals by its controls for touchpad, mouse buttons, and keyboard. First, hold the Connect button on the bottom left corner and enter the appropriate IP address for the socket. You can tap the top three quarters of the screen to test the Touchpad functionality to test that it sends the signals to the Go server. Use the bottom right button to pull up your keyboard and you can type to the computer. Finally, you can use the mouse in the bottom to simulate left clicks, right clicks, and middle clicks. You can also use touchpad gestures by tapping to left click, two-finger tapping to right click, and three-finger tapping to middle-click (the two-finger and three-finger tap gestures may not work if you are on Android). +The frontend can send signals by its controls for touchpad, mouse buttons, and keyboard. First, hold the Connect button on the bottom left corner and enter the appropriate IP address for the socket. You can tap the top three quarters of the screen to test the Touchpad functionality to test that it sends the signals to the Go server. Use the bottom right button to pull up your keyboard and you can type to the computer. Finally, you can use the mouse in the bottom to simulate left clicks, right clicks, and middle clicks. You can also use touchpad gestures by tapping to left click. Two-finger tapping to right click and three-finger tapping to middle click is currently only available for iOS. ## Project diff --git a/client/App.tsx b/client/App.tsx index f7a0676..18fec4b 100644 --- a/client/App.tsx +++ b/client/App.tsx @@ -6,6 +6,8 @@ import { Reconnect } from "./components/Reconnect"; import { Touchpad } from "./components/Touchpad"; import { ConnectModal } from "./components/ConnectModal"; +import { LongButtonContextProvider } from "./contexts/LongButtonContext"; + import { Dimensions, Image, @@ -15,24 +17,15 @@ import { import AsyncStorage from "@react-native-async-storage/async-storage"; -import { addressToString, connectSocket, convertIpAddress, mouseHandler } from "./utils"; -import { MouseButtons, MouseClicks } from "./utils"; +import { addressToString, connectSocket, convertIpAddress } from "./utils"; import { DEFAULT_ADDRESS } from "./utils"; - -export type Address = { - port: number, - host: string, -} +import { Address } from "./utils"; const App = () => { const [address, setAddress] = useState
(DEFAULT_ADDRESS); const [showConnectModal, setShowConnectModal] = useState(false); const [connect, setConnect] = useState(false); - const [toggleMouseLeft, setToggleMouseLeft] = useState(false); - const [toggleMouseMiddle, setToggleMouseMiddle] = useState(false); - const [toggleMouseRight, setToggleMouseRight] = useState(false); - useEffect(() => { (async () => { try { @@ -60,29 +53,6 @@ const App = () => { } }, [connect]) - const toggleLongButtonHandler = (button: MouseButtons, turn: boolean | null = null) => { - switch (button) { - case MouseButtons.LEFT: - setToggleMouseLeft((turn != null) ? turn : toggleMouseLeft ? false : true); - toggleMouseLeft - ? mouseHandler(MouseClicks.RELEASE, MouseButtons.LEFT) - : mouseHandler(MouseClicks.PRESS, MouseButtons.LEFT); - break; - case MouseButtons.MIDDLE: - setToggleMouseMiddle((turn != null) ? turn : toggleMouseMiddle ? false : true); - toggleMouseMiddle - ? mouseHandler(MouseClicks.RELEASE, MouseButtons.MIDDLE) - : mouseHandler(MouseClicks.PRESS, MouseButtons.MIDDLE); - break; - case MouseButtons.RIGHT: - setToggleMouseRight((turn != null) ? turn : toggleMouseRight ? false : true); - toggleMouseRight - ? mouseHandler(MouseClicks.RELEASE, MouseButtons.RIGHT) - : mouseHandler(MouseClicks.PRESS, MouseButtons.RIGHT); - break; - } - } - return ( <> @@ -98,18 +68,10 @@ const App = () => { setShowConnectModal={setShowConnectModal} /> } - - + + + + void, - toggleMouseLeft: boolean, - toggleMouseMiddle: boolean, - toggleMouseRight: boolean, -} - -export const MouseClick = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouseMiddle, toggleMouseRight }: Props) => { +export const MouseClick = () => { const [clickedButton, setClickedButton] = useState(null); + const { toggleMouseLeft, toggleMouseMiddle, toggleMouseRight } = useContext(LongButtonStateContext); + const longButtonDispatch = useContext(LongButtonDispatchContext); + const handleClick = (button: MouseButtons) => { setClickedButton(button); setTimeout(() => setClickedButton(null), 100); @@ -29,9 +26,9 @@ export const MouseClick = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMou toggleMouseLeft - ? toggleLongButtonHandler(MouseButtons.LEFT) + ? longButtonDispatch({ button: MouseButtons.LEFT }) : handleClick(MouseButtons.LEFT)} - onLongPress={() => toggleLongButtonHandler(MouseButtons.LEFT)} + onLongPress={() => longButtonDispatch({ button: MouseButtons.LEFT })} > toggleMouseMiddle - ? toggleLongButtonHandler(MouseButtons.MIDDLE) + ? longButtonDispatch({ button: MouseButtons.MIDDLE }) : handleClick(MouseButtons.MIDDLE)} - onLongPress={() => toggleLongButtonHandler(MouseButtons.MIDDLE)} + onLongPress={() => longButtonDispatch({ button: MouseButtons.MIDDLE })} > toggleMouseRight - ? toggleLongButtonHandler(MouseButtons.RIGHT) + ? longButtonDispatch({ button: MouseButtons.RIGHT }) : handleClick(MouseButtons.RIGHT)} - onLongPress={() => toggleLongButtonHandler(MouseButtons.RIGHT)} + onLongPress={() => longButtonDispatch({ button: MouseButtons.RIGHT })} > void, - toggleMouseLeft: boolean, - toggleMouseMiddle: boolean, - toggleMouseRight: boolean, -} - -export const Touchpad = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouseMiddle, toggleMouseRight }: Props) => { +export const Touchpad = () => { const [prevPosition, setPrevPosition] = useState(null); const [position, setPosition] = useState(null); const [prevScroll, setPrevScroll] = useState(null); @@ -28,6 +24,9 @@ export const Touchpad = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouse const [tap, setTap] = useState(null); const [time, setTime] = useState(Date.now().valueOf()); + const { toggleMouseLeft, toggleMouseMiddle, toggleMouseRight } = useContext(LongButtonStateContext); + const longButtonDispatch = useContext(LongButtonDispatchContext); + const isNumFingers = (finger: number, event: GestureResponderEvent) => event.nativeEvent.touches.length == finger; const getCurrentPosition = (event: GestureResponderEvent)=> { @@ -41,8 +40,8 @@ export const Touchpad = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouse const gestureHandler = (responder: Responder, event: GestureResponderEvent) => { if (responder == Responder.START) { if (isNumFingers(1, event)) setTap(Tap.One); - if (isNumFingers(2, event)) setTap(Tap.Two); - if (isNumFingers(3, event)) setTap(Tap.Three); + if (Platform.OS != "android") if (isNumFingers(2, event)) setTap(Tap.Two); + if (Platform.OS != "android") if (isNumFingers(3, event)) setTap(Tap.Three); setTime(Date.now().valueOf()); } @@ -70,15 +69,15 @@ export const Touchpad = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouse if (tap) switch ((tap as unknown) as MouseButtons) { case MouseButtons.LEFT: - if (toggleMouseLeft) toggleLongButtonHandler(MouseButtons.LEFT) + if (toggleMouseLeft) longButtonDispatch({ button: MouseButtons.LEFT }) else mouseHandler(MouseClicks.CLICK, MouseButtons.LEFT); break; case MouseButtons.MIDDLE: - if (toggleMouseMiddle) toggleLongButtonHandler(MouseButtons.MIDDLE) + if (toggleMouseMiddle) longButtonDispatch({ button: MouseButtons.MIDDLE }) else mouseHandler(MouseClicks.CLICK, MouseButtons.MIDDLE); break; case MouseButtons.RIGHT: - if (toggleMouseRight) toggleLongButtonHandler(MouseButtons.RIGHT) + if (toggleMouseRight) longButtonDispatch({ button: MouseButtons.RIGHT }) else mouseHandler(MouseClicks.CLICK, MouseButtons.RIGHT); break; } diff --git a/client/contexts/LongButtonContext.tsx b/client/contexts/LongButtonContext.tsx new file mode 100644 index 0000000..8a05366 --- /dev/null +++ b/client/contexts/LongButtonContext.tsx @@ -0,0 +1,64 @@ +import React, { useReducer } from "react"; + +import { mouseHandler } from "../utils"; +import { MouseButtons, MouseClicks } from "../utils"; + +type LongButtonActions = { + button: MouseButtons, + turn?: boolean, +} + +const initialLongButtonState = { + toggleMouseLeft: false, + toggleMouseMiddle: false, + toggleMouseRight: false, +}; + +export const LongButtonStateContext = React.createContext(initialLongButtonState); +export const LongButtonDispatchContext = React.createContext>(() => null); + +export const LongButtonContextProvider = ({ children }: { children: React.ReactNode }) => { + const [longButtonStates, longButtonDispatch] = useReducer(LongButtonReducer, initialLongButtonState); + + return ( + + + { children } + + + ); +} + +const LongButtonReducer = (states: typeof initialLongButtonState, + action: LongButtonActions) => { + const { button, turn } = action; + const { toggleMouseLeft, toggleMouseMiddle, toggleMouseRight } = states; + switch (button) { + case MouseButtons.LEFT: + toggleMouseLeft + ? mouseHandler(MouseClicks.RELEASE, MouseButtons.LEFT) + : mouseHandler(MouseClicks.PRESS, MouseButtons.LEFT); + return { + ...states, + toggleMouseLeft: (turn != undefined) ? turn : toggleMouseLeft ? false : true, + }; + case MouseButtons.MIDDLE: + toggleMouseMiddle + ? mouseHandler(MouseClicks.RELEASE, MouseButtons.MIDDLE) + : mouseHandler(MouseClicks.PRESS, MouseButtons.MIDDLE); + return { + ...states, + toggleMouseMiddle: (turn != undefined) ? turn : toggleMouseMiddle ? false : true, + }; + case MouseButtons.RIGHT: + toggleMouseRight + ? mouseHandler(MouseClicks.RELEASE, MouseButtons.RIGHT) + : mouseHandler(MouseClicks.PRESS, MouseButtons.RIGHT); + return { + ...states, + toggleMouseRight: (turn != undefined) ? turn : toggleMouseRight ? false : true, + }; + default: + return states; + } +} diff --git a/client/tsconfig.json b/client/tsconfig.json index f5d7657..b9e6fa3 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -14,6 +14,8 @@ "allowSyntheticDefaultImports": true, "esModuleInterop": true, "skipLibCheck": false, + "declaration": true, + "declarationDir": "./@types/ultraviolet", }, "exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"] } diff --git a/client/utils.ts b/client/utils.ts index bafc4eb..be94333 100644 --- a/client/utils.ts +++ b/client/utils.ts @@ -1,22 +1,15 @@ import TcpSocket from "react-native-tcp-socket"; -import { Address } from "./App"; +// Default constants export let client: TcpSocket.Socket; export const DEFAULT_TEXT_VALUE = " "; export const DEFAULT_ADDRESS: Address = { port: 27001, host: "localhost" }; const DEFAULT_STRING_LIMIT = 30; const DEFAULT_DECIMAL_PLACE = 0; -export enum MouseClicks { - CLICK = "c", - PRESS= "p", - RELEASE = "r" -} - -export enum MouseButtons { - LEFT = "l", - MIDDLE = "m", - RIGHT = "r" +export type Address = { + port: number, + host: string, } export type Position = { @@ -29,6 +22,18 @@ export type ScrollPosition = { secondY: number, } +export enum MouseClicks { + CLICK = "c", + PRESS= "p", + RELEASE = "r" +} + +export enum MouseButtons { + LEFT = "l", + MIDDLE = "m", + RIGHT = "r" +} + enum FunctionKey { BACKSPACE = "backspace", ENTER = "enter",