Skip to content

Commit

Permalink
Add virtual textbox for easier keyboard entry (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxminoS authored May 19, 2021
1 parent 11e10ca commit 24bb2ee
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 9 deletions.
25 changes: 21 additions & 4 deletions client/components/OpenKeyboard.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React, { useState, useEffect, useRef } from "react";

import { VirtualText } from "./VirtualText";
import {
Dimensions,
Image,
Keyboard,
KeyboardEvent,
Platform,
StyleSheet,
TextInput,
TouchableWithoutFeedback,
View
} from "react-native";

import { keyboardHandler } from "../utils";
import { DEFAULT_TEXT_VALUE } from "../utils";

enum KeyboardButtons { Up, Down }
Expand All @@ -20,6 +21,8 @@ export const OpenKeyboard = () => {
const [keyPress, setKeyPress] = useState<string>(DEFAULT_TEXT_VALUE);
const [keyboardShowing, setKeyboardShowing] = useState(false);
const [clickedButton, setClickedButton] = useState<KeyboardButtons | null>(null);
const [virtualTextHandler, setVirtualTextHandler] = useState("");
const [keyboardHeight, setKeyboardHeight] = useState(0);
const inputRef = useRef<TextInput>(null);

useEffect(() => {
Expand All @@ -33,13 +36,20 @@ export const OpenKeyboard = () => {

useEffect(() => {
if (keyPress != DEFAULT_TEXT_VALUE) {
keyboardHandler(keyPress);
setVirtualTextHandler(keyPress);
setKeyPress(DEFAULT_TEXT_VALUE);
}
}, [keyPress]);

const showKeyboard = () => setKeyboardShowing(true);
const hideKeyboard = () => setKeyboardShowing(false);
const showKeyboard = (e: KeyboardEvent) => {
setKeyboardHeight(e.endCoordinates.height);
setKeyboardShowing(true);
}

const hideKeyboard = () => {
setKeyboardHeight(0);
setKeyboardShowing(false);
}

const handlePress = () => {
setClickedButton(KeyboardButtons.Up);
Expand Down Expand Up @@ -82,6 +92,13 @@ export const OpenKeyboard = () => {
/>
</TouchableWithoutFeedback>
</View>
{ keyboardShowing &&
<VirtualText
virtualTextHandler={virtualTextHandler}
setVirtualTextHandler={setVirtualTextHandler}
keyboardHeight={keyboardHeight}
/>
}
<TextInput
ref={inputRef}
onChangeText={setKeyPress}
Expand Down
99 changes: 99 additions & 0 deletions client/components/VirtualText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React, { useState, useEffect } from "react";

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

import { keyboardHandler } from "../utils";
import { DEFAULT_TEXT_VALUE } from "../utils";

type Props = {
virtualTextHandler: string,
setVirtualTextHandler: React.Dispatch<React.SetStateAction<string>>,
keyboardHeight: number,
}

const TEXT_TIMEOUT = 5000;

export const VirtualText = ({ virtualTextHandler, setVirtualTextHandler, keyboardHeight }: Props) => {
const [virtualText, setVirtualText] = useState("");
const [showText, setShowText] = useState<NodeJS.Timeout | null>(null);

useEffect(() => {
if (virtualTextHandler != DEFAULT_TEXT_VALUE) {
let text = keyboardHandler(virtualTextHandler);
switch (text) {
case "":
break;
case 0:
setVirtualText("");
break;
case -1: // Backspace
setVirtualText(virtualText.substring(0, virtualText.length - 1));
clearWithin();
break;
default:
setVirtualText(virtualText + text);
clearWithin();
break;
}
setVirtualTextHandler(DEFAULT_TEXT_VALUE);
return () => {
text = "";
};
}
}, [virtualTextHandler]);

// Reset timeout
const clearWithin = () => {
showText && clearTimeout(showText);
setShowText(setTimeout(() => {
setVirtualText("");
setShowText(null);
}, TEXT_TIMEOUT));
}

return (
<>
{ virtualText
? <View style={stylesContainer(keyboardHeight).textBox}>
<Text
numberOfLines={1}
ellipsizeMode="head"
style={styles.text}
>
{ virtualText }
</Text>
</View>
: <></>
}
</>
)
}

const styles = StyleSheet.create({
text: {
color: "white",
fontSize: 18,
fontWeight: "400",
},
});

const stylesContainer = (keyboardHeight: Props["keyboardHeight"]) => StyleSheet.create({
textBox: {
position: "absolute",
bottom: (Platform.OS == "android" && StatusBar.currentHeight)
? keyboardHeight + StatusBar.currentHeight
: keyboardHeight,
alignItems: "center",
justifyContent: "center",
width: "100%",
height: 40,
backgroundColor: "#1B1134",
zIndex: -1,
},
});
10 changes: 5 additions & 5 deletions client/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,16 @@ export const mouseScroll = (previous: ScrollPosition, current: ScrollPosition) =
// Keyboard
// k<key...> -- Key <enter, backspace> [OpenKeyboard]
// t<text> -- Type [OpenKeyboard]
export const keyboardHandler = (keyPress: string) => {
export const keyboardHandler = (keyPress: string): string | number => {
// Function keys
if (keyPress == FunctionKeyNotation.BACKSPACE) {
sendMessage("k" + FunctionKey.BACKSPACE);
return;
return -1;
}
keyPress = keyPress.substring(1, keyPress.length);
if (keyPress == FunctionKeyNotation.ENTER) {
sendMessage("k" + FunctionKey.ENTER);
return;
return 0;
}

// Long string
Expand All @@ -128,11 +128,11 @@ export const keyboardHandler = (keyPress: string) => {
stringArray = limitString([], keyPress, DEFAULT_STRING_LIMIT);
for (let string in stringArray)
sendMessage("t" + stringArray[string]);
return;
return keyPress;
}
// Key presses
sendMessage("t" + keyPress);
return;
return keyPress;
}

const limitString = (limitedStrings: string[], string: string, limit: number) => {
Expand Down

0 comments on commit 24bb2ee

Please sign in to comment.