Compare commits

...

4 Commits

Author SHA1 Message Date
Tom Wopat d3ad614b83
Merge dc7791c245 into 703625d59a 2025-09-25 04:26:15 -04:00
Adam Shiervani 703625d59a
fix: faster paste speed (#824)
* fix: update delay handling in PasteModal component

- Changed default delay value to 20 and adjusted validation to allow values between 0 and 65534.
- Cleaned up code formatting for better readability.

* fix: formatting
2025-09-25 10:26:11 +02:00
Tom Wopat dc7791c245 feat: add fullscreen button 2025-09-23 23:50:06 -04:00
Tom Wopat 9affd248f3 feat: allow pointer lock when no video 2025-09-23 23:50:05 -04:00
3 changed files with 31 additions and 17 deletions

View File

@ -2,7 +2,7 @@ import React from "react";
import { ExclamationTriangleIcon } from "@heroicons/react/24/solid"; import { ExclamationTriangleIcon } from "@heroicons/react/24/solid";
import { ArrowPathIcon, ArrowRightIcon } from "@heroicons/react/16/solid"; import { ArrowPathIcon, ArrowRightIcon } from "@heroicons/react/16/solid";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import { LuPlay } from "react-icons/lu"; import { LuMaximize, LuPlay } from "react-icons/lu";
import { BsMouseFill } from "react-icons/bs"; import { BsMouseFill } from "react-icons/bs";
import { Button, LinkButton } from "@components/Button"; import { Button, LinkButton } from "@components/Button";
@ -209,9 +209,10 @@ export function PeerConnectionDisconnectedOverlay({
interface HDMIErrorOverlayProps { interface HDMIErrorOverlayProps {
readonly show: boolean; readonly show: boolean;
readonly hdmiState: string; readonly hdmiState: string;
readonly requestFullscreen: () => void;
} }
export function HDMIErrorOverlay({ show, hdmiState }: HDMIErrorOverlayProps) { export function HDMIErrorOverlay({ show, hdmiState, requestFullscreen }: HDMIErrorOverlayProps) {
const isNoSignal = hdmiState === "no_signal"; const isNoSignal = hdmiState === "no_signal";
const isOtherError = hdmiState === "no_lock" || hdmiState === "out_of_range"; const isOtherError = hdmiState === "no_lock" || hdmiState === "out_of_range";
@ -247,14 +248,25 @@ export function HDMIErrorOverlay({ show, hdmiState }: HDMIErrorOverlayProps) {
</li> </li>
</ul> </ul>
</div> </div>
<div> <div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2 py-1.5">
<LinkButton <div className="relative flex flex-wrap items-center gap-x-2 gap-y-2">
to={"https://jetkvm.com/docs/getting-started/troubleshooting"} <LinkButton
theme="light" to={"https://jetkvm.com/docs/getting-started/troubleshooting"}
text="Learn more" theme="light"
TrailingIcon={ArrowRightIcon} text="Learn more"
size="SM" TrailingIcon={ArrowRightIcon}
/> size="SM"
/>
</div>
<div className="flex flex-wrap items-right gap-x-2 gap-y-2">
<Button
size="XS"
theme="light"
text="Fullscreen"
LeadingIcon={LuMaximize}
onClick={() => requestFullscreen()}
/>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -542,9 +542,9 @@ export default function WebRTCVideo() {
style={{ animationDuration: "500ms" }} style={{ animationDuration: "500ms" }}
className="animate-slideUpFade pointer-events-none absolute inset-0 flex items-center justify-center" className="animate-slideUpFade pointer-events-none absolute inset-0 flex items-center justify-center"
> >
<div className="relative h-full w-full rounded-md"> <div className="relative h-full w-full rounded-md" onClick={requestPointerLock}>
<LoadingVideoOverlay show={isVideoLoading} /> <LoadingVideoOverlay show={isVideoLoading} />
<HDMIErrorOverlay show={hdmiError} hdmiState={hdmiState} /> <HDMIErrorOverlay show={hdmiError} hdmiState={hdmiState} requestFullscreen={requestFullscreen}/>
<NoAutoplayPermissionsOverlay <NoAutoplayPermissionsOverlay
show={hasNoAutoPlayPermissions} show={hasNoAutoPlayPermissions}
onPlayClick={() => { onPlayClick={() => {

View File

@ -17,6 +17,7 @@ import { TextAreaWithLabel } from "@components/TextArea";
// uint32 max value / 4 // uint32 max value / 4
const pasteMaxLength = 1073741824; const pasteMaxLength = 1073741824;
const defaultDelay = 20;
export default function PasteModal() { export default function PasteModal() {
const TextAreaRef = useRef<HTMLTextAreaElement>(null); const TextAreaRef = useRef<HTMLTextAreaElement>(null);
@ -27,10 +28,10 @@ export default function PasteModal() {
const { executeMacro, cancelExecuteMacro } = useKeyboard(); const { executeMacro, cancelExecuteMacro } = useKeyboard();
const [invalidChars, setInvalidChars] = useState<string[]>([]); const [invalidChars, setInvalidChars] = useState<string[]>([]);
const [delayValue, setDelayValue] = useState(100); const [delayValue, setDelayValue] = useState(defaultDelay);
const delay = useMemo(() => { const delay = useMemo(() => {
if (delayValue < 50 || delayValue > 65534) { if (delayValue < 0 || delayValue > 65534) {
return 100; return defaultDelay;
} }
return delayValue; return delayValue;
}, [delayValue]); }, [delayValue]);
@ -40,7 +41,7 @@ export default function PasteModal() {
const delayClassName = useMemo(() => debugMode ? "" : "hidden", [debugMode]); const delayClassName = useMemo(() => debugMode ? "" : "hidden", [debugMode]);
const { setKeyboardLayout } = useSettingsStore(); const { setKeyboardLayout } = useSettingsStore();
const { selectedKeyboard } = useKeyboardLayout(); const { selectedKeyboard } = useKeyboardLayout();
useEffect(() => { useEffect(() => {
send("getKeyboardLayout", {}, (resp: JsonRpcResponse) => { send("getKeyboardLayout", {}, (resp: JsonRpcResponse) => {
@ -136,7 +137,8 @@ export default function PasteModal() {
<div <div
className="w-full" className="w-full"
onKeyUp={e => e.stopPropagation()} onKeyUp={e => e.stopPropagation()}
onKeyDown={e => e.stopPropagation()} onKeyDownCapture={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()}
onKeyDownCapture={e => e.stopPropagation()}
onKeyUpCapture={e => e.stopPropagation()} onKeyUpCapture={e => e.stopPropagation()}
> >
<TextAreaWithLabel <TextAreaWithLabel