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",