Skip to content

Commit

Permalink
Clean up and optimize codebase with more readable code (#36)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
maxminoS authored May 14, 2021
1 parent 0019ee3 commit 11e10ca
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 90 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
54 changes: 8 additions & 46 deletions client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<Address>(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 {
Expand Down Expand Up @@ -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 (
<>
<SafeAreaView style={styles.scrollView}>
Expand All @@ -98,18 +68,10 @@ const App = () => {
setShowConnectModal={setShowConnectModal}
/>
}
<Touchpad
toggleLongButtonHandler={toggleLongButtonHandler}
toggleMouseLeft={toggleMouseLeft}
toggleMouseMiddle={toggleMouseMiddle}
toggleMouseRight={toggleMouseRight}
/>
<MouseClick
toggleLongButtonHandler={toggleLongButtonHandler}
toggleMouseLeft={toggleMouseLeft}
toggleMouseMiddle={toggleMouseMiddle}
toggleMouseRight={toggleMouseRight}
/>
<LongButtonContextProvider>
<Touchpad />
<MouseClick />
</LongButtonContextProvider>
<Reconnect
setConnect={setConnect}
setShowConnectModal={setShowConnectModal}
Expand Down
2 changes: 1 addition & 1 deletion client/components/ConnectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
View
} from "react-native";

import { Address } from "../App";
import { convertIpAddress, addressToString } from "../utils";
import { DEFAULT_ADDRESS } from "../utils";
import { Address } from "../utils";

type Props = {
address: Address,
Expand Down
27 changes: 12 additions & 15 deletions client/components/MouseClick.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState } from "react";
import React, { useState, useContext } from "react";
import { LongButtonStateContext, LongButtonDispatchContext } from "../contexts/LongButtonContext";
import { MouseButtons, MouseClicks } from "../utils";
import { mouseHandler } from "../utils";

Expand All @@ -9,16 +10,12 @@ import {
View
} from "react-native";

type Props = {
toggleLongButtonHandler: (button: MouseButtons, turn?: boolean | null) => void,
toggleMouseLeft: boolean,
toggleMouseMiddle: boolean,
toggleMouseRight: boolean,
}

export const MouseClick = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouseMiddle, toggleMouseRight }: Props) => {
export const MouseClick = () => {
const [clickedButton, setClickedButton] = useState<MouseButtons | null>(null);

const { toggleMouseLeft, toggleMouseMiddle, toggleMouseRight } = useContext(LongButtonStateContext);
const longButtonDispatch = useContext(LongButtonDispatchContext);

const handleClick = (button: MouseButtons) => {
setClickedButton(button);
setTimeout(() => setClickedButton(null), 100);
Expand All @@ -29,9 +26,9 @@ export const MouseClick = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMou
<View style={styles.footer}>
<TouchableWithoutFeedback
onPress={() => toggleMouseLeft
? toggleLongButtonHandler(MouseButtons.LEFT)
? longButtonDispatch({ button: MouseButtons.LEFT })
: handleClick(MouseButtons.LEFT)}
onLongPress={() => toggleLongButtonHandler(MouseButtons.LEFT)}
onLongPress={() => longButtonDispatch({ button: MouseButtons.LEFT })}
>
<Image
source={(toggleMouseLeft || (clickedButton == MouseButtons.LEFT))
Expand All @@ -44,9 +41,9 @@ export const MouseClick = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMou
<View style={styles.center}>
<TouchableWithoutFeedback
onPress={() => toggleMouseMiddle
? toggleLongButtonHandler(MouseButtons.MIDDLE)
? longButtonDispatch({ button: MouseButtons.MIDDLE })
: handleClick(MouseButtons.MIDDLE)}
onLongPress={() => toggleLongButtonHandler(MouseButtons.MIDDLE)}
onLongPress={() => longButtonDispatch({ button: MouseButtons.MIDDLE })}
>
<Image
source={(toggleMouseMiddle || (clickedButton == MouseButtons.MIDDLE))
Expand All @@ -59,9 +56,9 @@ export const MouseClick = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMou
</View>
<TouchableWithoutFeedback
onPress={() => toggleMouseRight
? toggleLongButtonHandler(MouseButtons.RIGHT)
? longButtonDispatch({ button: MouseButtons.RIGHT })
: handleClick(MouseButtons.RIGHT)}
onLongPress={() => toggleLongButtonHandler(MouseButtons.RIGHT)}
onLongPress={() => longButtonDispatch({ button: MouseButtons.RIGHT })}
>
<Image
source={(toggleMouseRight || (clickedButton == MouseButtons.RIGHT))
Expand Down
31 changes: 15 additions & 16 deletions client/components/Touchpad.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
import React, { useState } from "react";
import React, { useState, useContext } from "react";

import { GestureResponderEvent,
Platform,
StyleSheet,
View
} from "react-native";

import { LongButtonStateContext, LongButtonDispatchContext } from "../contexts/LongButtonContext";
import { mouseMove, mouseScroll, mouseHandler } from "../utils";
import { Position, ScrollPosition, MouseButtons, MouseClicks } from "../utils";
import { MouseButtons, MouseClicks } from "../utils";
import { Position, ScrollPosition } from "../utils";

enum Responder { START, MOVE, RELEASE }
enum Tap { One = MouseButtons.LEFT, Two = MouseButtons.RIGHT, Three = MouseButtons.MIDDLE }

const TAP_INTERVAL = 250;
const TAP_INTERVAL = 100;

type Props = {
toggleLongButtonHandler: (button: MouseButtons, turn?: boolean | null) => void,
toggleMouseLeft: boolean,
toggleMouseMiddle: boolean,
toggleMouseRight: boolean,
}

export const Touchpad = ({ toggleLongButtonHandler, toggleMouseLeft, toggleMouseMiddle, toggleMouseRight }: Props) => {
export const Touchpad = () => {
const [prevPosition, setPrevPosition] = useState<Position | null>(null);
const [position, setPosition] = useState<Position | null>(null);
const [prevScroll, setPrevScroll] = useState<ScrollPosition | null>(null);
const [scroll, setScroll] = useState<ScrollPosition | null>(null);
const [tap, setTap] = useState<Tap | null>(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)=> {
Expand All @@ -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());
}

Expand Down Expand Up @@ -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;
}
Expand Down
64 changes: 64 additions & 0 deletions client/contexts/LongButtonContext.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof initialLongButtonState>(initialLongButtonState);
export const LongButtonDispatchContext = React.createContext<React.Dispatch<LongButtonActions>>(() => null);

export const LongButtonContextProvider = ({ children }: { children: React.ReactNode }) => {
const [longButtonStates, longButtonDispatch] = useReducer(LongButtonReducer, initialLongButtonState);

return (
<LongButtonStateContext.Provider value={longButtonStates}>
<LongButtonDispatchContext.Provider value={longButtonDispatch}>
{ children }
</LongButtonDispatchContext.Provider>
</LongButtonStateContext.Provider>
);
}

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;
}
}
2 changes: 2 additions & 0 deletions client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
}
27 changes: 16 additions & 11 deletions client/utils.ts
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -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",
Expand Down

0 comments on commit 11e10ca

Please sign in to comment.