refactor: remove scroll sensitivity functionality and clean up related code (#477)

- Removed scroll sensitivity state and associated functions from jsonrpc.go and WebRTCVideo component.
- Cleaned up device settings store by eliminating unused scroll sensitivity logic.
- Updated mouse settings route to reflect the removal of scroll sensitivity feature.
- Simplified mouse wheel event handling in WebRTCVideo component.
This commit is contained in:
Adam Shiervani 2025-05-19 22:44:53 +02:00 committed by GitHub
parent 7a9fb7cbb1
commit 3f320e50f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 174 additions and 958 deletions

View File

@ -877,17 +877,6 @@ func rpcSetCloudUrl(apiUrl string, appUrl string) error {
return nil return nil
} }
var currentScrollSensitivity string = "default"
func rpcGetScrollSensitivity() (string, error) {
return currentScrollSensitivity, nil
}
func rpcSetScrollSensitivity(sensitivity string) error {
currentScrollSensitivity = sensitivity
return nil
}
func getKeyboardMacros() (interface{}, error) { func getKeyboardMacros() (interface{}, error) {
macros := make([]KeyboardMacro, len(config.KeyboardMacros)) macros := make([]KeyboardMacro, len(config.KeyboardMacros))
copy(macros, config.KeyboardMacros) copy(macros, config.KeyboardMacros)
@ -1053,8 +1042,6 @@ var rpcHandlers = map[string]RPCHandler{
"setUsbDevices": {Func: rpcSetUsbDevices, Params: []string{"devices"}}, "setUsbDevices": {Func: rpcSetUsbDevices, Params: []string{"devices"}},
"setUsbDeviceState": {Func: rpcSetUsbDeviceState, Params: []string{"device", "enabled"}}, "setUsbDeviceState": {Func: rpcSetUsbDeviceState, Params: []string{"device", "enabled"}},
"setCloudUrl": {Func: rpcSetCloudUrl, Params: []string{"apiUrl", "appUrl"}}, "setCloudUrl": {Func: rpcSetCloudUrl, Params: []string{"apiUrl", "appUrl"}},
"getScrollSensitivity": {Func: rpcGetScrollSensitivity},
"setScrollSensitivity": {Func: rpcSetScrollSensitivity, Params: []string{"sensitivity"}},
"getKeyboardMacros": {Func: getKeyboardMacros}, "getKeyboardMacros": {Func: getKeyboardMacros},
"setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}}, "setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}},
} }

891
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useResizeObserver } from "usehooks-ts"; import { useResizeObserver } from "usehooks-ts";
import { import {
useDeviceSettingsStore,
useHidStore, useHidStore,
useMouseStore, useMouseStore,
useRTCStore, useRTCStore,
@ -61,7 +60,6 @@ export default function WebRTCVideo() {
useHidStore(); useHidStore();
// Misc states and hooks // Misc states and hooks
const [blockWheelEvent, setBlockWheelEvent] = useState(false);
const disableVideoFocusTrap = useUiStore(state => state.disableVideoFocusTrap); const disableVideoFocusTrap = useUiStore(state => state.disableVideoFocusTrap);
const [send] = useJsonRpc(); const [send] = useJsonRpc();
@ -248,17 +246,8 @@ export default function WebRTCVideo() {
], ],
); );
const trackpadSensitivity = useDeviceSettingsStore(state => state.trackpadSensitivity);
const mouseSensitivity = useDeviceSettingsStore(state => state.mouseSensitivity);
const clampMin = useDeviceSettingsStore(state => state.clampMin);
const clampMax = useDeviceSettingsStore(state => state.clampMax);
const blockDelay = useDeviceSettingsStore(state => state.blockDelay);
const trackpadThreshold = useDeviceSettingsStore(state => state.trackpadThreshold);
const mouseWheelHandler = useCallback( const mouseWheelHandler = useCallback(
(e: WheelEvent) => { (e: WheelEvent) => {
if (blockWheelEvent) return;
// Determine if the wheel event is an accel scroll value // Determine if the wheel event is an accel scroll value
const isAccel = Math.abs(e.deltaY) >= 100; const isAccel = Math.abs(e.deltaY) >= 100;
@ -266,7 +255,7 @@ export default function WebRTCVideo() {
const accelScrollValue = e.deltaY / 100; const accelScrollValue = e.deltaY / 100;
// Calculate the no accel scroll value // Calculate the no accel scroll value
const noAccelScrollValue = e.deltaY > 0 ? 1 : (e.deltaY < 0 ? -1 : 0); const noAccelScrollValue = e.deltaY > 0 ? 1 : e.deltaY < 0 ? -1 : 0;
// Get scroll value // Get scroll value
const scrollValue = isAccel ? accelScrollValue : noAccelScrollValue; const scrollValue = isAccel ? accelScrollValue : noAccelScrollValue;
@ -277,22 +266,9 @@ export default function WebRTCVideo() {
// Invert the clamped scroll value to match expected behavior // Invert the clamped scroll value to match expected behavior
const invertedScrollValue = -clampedScrollValue; const invertedScrollValue = -clampedScrollValue;
send("wheelReport", { wheelY : invertedScrollValue }); send("wheelReport", { wheelY: invertedScrollValue });
// Apply blocking delay
setBlockWheelEvent(true);
setTimeout(() => setBlockWheelEvent(false), blockDelay);
}, },
[ [send],
blockDelay,
blockWheelEvent,
clampMax,
clampMin,
mouseSensitivity,
send,
trackpadSensitivity,
trackpadThreshold,
],
); );
const resetMousePosition = useCallback(() => { const resetMousePosition = useCallback(() => {
@ -351,11 +327,7 @@ export default function WebRTCVideo() {
// which means the Alt Gr key state would then be "stuck". At this // which means the Alt Gr key state would then be "stuck". At this
// point, we would need to rely on the user to press Alt Gr again // point, we would need to rely on the user to press Alt Gr again
// to properly release the state of that modifier. // to properly release the state of that modifier.
.filter( .filter(modifier => altKey || modifier !== modifiers["AltLeft"])
modifier =>
altKey ||
(modifier !== modifiers["AltLeft"]),
)
// Meta: Keep if Meta is pressed or if the key isn't a Meta key // Meta: Keep if Meta is pressed or if the key isn't a Meta key
// Example: If metaKey is true, keep all modifiers // Example: If metaKey is true, keep all modifiers
// If metaKey is false, filter out 0x08 (MetaLeft) and 0x80 (MetaRight) // If metaKey is false, filter out 0x08 (MetaLeft) and 0x80 (MetaRight)
@ -716,7 +688,7 @@ export default function WebRTCVideo() {
disablePictureInPicture disablePictureInPicture
controlsList="nofullscreen" controlsList="nofullscreen"
className={cx( className={cx(
"z-30 max-h-full min-h-[384px] min-w-[512px] max-w-full bg-black/50 object-contain transition-all duration-1000", "z-30 max-h-full min-h-[384px] max-w-full min-w-[512px] bg-black/50 object-contain transition-all duration-1000",
{ {
"cursor-none": settings.isCursorHidden, "cursor-none": settings.isCursorHidden,
"opacity-0": "opacity-0":
@ -732,7 +704,7 @@ export default function WebRTCVideo() {
{peerConnection?.connectionState == "connected" && ( {peerConnection?.connectionState == "connected" && (
<div <div
style={{ animationDuration: "500ms" }} style={{ animationDuration: "500ms" }}
className="pointer-events-none absolute inset-0 flex animate-slideUpFade 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">
<LoadingVideoOverlay show={isVideoLoading} /> <LoadingVideoOverlay show={isVideoLoading} />

View File

@ -321,8 +321,7 @@ export const useSettingsStore = create(
setDeveloperMode: enabled => set({ developerMode: enabled }), setDeveloperMode: enabled => set({ developerMode: enabled }),
displayRotation: "270", displayRotation: "270",
setDisplayRotation: (rotation: string) => setDisplayRotation: (rotation: string) => set({ displayRotation: rotation }),
set({ displayRotation: rotation }),
backlightSettings: { backlightSettings: {
max_brightness: 100, max_brightness: 100,
@ -350,67 +349,6 @@ export interface DeviceSettingsState {
setScrollSensitivity: (sensitivity: DeviceSettingsState["scrollSensitivity"]) => void; setScrollSensitivity: (sensitivity: DeviceSettingsState["scrollSensitivity"]) => void;
} }
export const useDeviceSettingsStore = create<DeviceSettingsState>(set => ({
trackpadSensitivity: 3.0,
mouseSensitivity: 5.0,
clampMin: -8,
clampMax: 8,
blockDelay: 25,
trackpadThreshold: 10,
scrollSensitivity: "default",
setScrollSensitivity: sensitivity => {
const wheelSettings: Record<
DeviceSettingsState["scrollSensitivity"],
{
trackpadSensitivity: DeviceSettingsState["trackpadSensitivity"];
mouseSensitivity: DeviceSettingsState["mouseSensitivity"];
clampMin: DeviceSettingsState["clampMin"];
clampMax: DeviceSettingsState["clampMax"];
blockDelay: DeviceSettingsState["blockDelay"];
trackpadThreshold: DeviceSettingsState["trackpadThreshold"];
}
> = {
low: {
trackpadSensitivity: 2.0,
mouseSensitivity: 3.0,
clampMin: -6,
clampMax: 6,
blockDelay: 30,
trackpadThreshold: 10,
},
default: {
trackpadSensitivity: 3.0,
mouseSensitivity: 5.0,
clampMin: -8,
clampMax: 8,
blockDelay: 25,
trackpadThreshold: 10,
},
high: {
trackpadSensitivity: 4.0,
mouseSensitivity: 6.0,
clampMin: -9,
clampMax: 9,
blockDelay: 20,
trackpadThreshold: 10,
},
};
const settings = wheelSettings[sensitivity];
return set({
trackpadSensitivity: settings.trackpadSensitivity,
trackpadThreshold: settings.trackpadThreshold,
mouseSensitivity: settings.mouseSensitivity,
clampMin: settings.clampMin,
clampMax: settings.clampMax,
blockDelay: settings.blockDelay,
scrollSensitivity: sensitivity,
});
},
}));
export interface RemoteVirtualMediaState { export interface RemoteVirtualMediaState {
source: "WebRTC" | "HTTP" | "Storage" | null; source: "WebRTC" | "HTTP" | "Storage" | null;
mode: "CDROM" | "Disk" | null; mode: "CDROM" | "Disk" | null;

View File

@ -1,23 +1,20 @@
import { CheckCircleIcon } from "@heroicons/react/16/solid"; import { CheckCircleIcon } from "@heroicons/react/16/solid";
import { useCallback, useEffect, useState } from "react"; import { useEffect, useState } from "react";
import MouseIcon from "@/assets/mouse-icon.svg"; import MouseIcon from "@/assets/mouse-icon.svg";
import PointingFinger from "@/assets/pointing-finger.svg"; import PointingFinger from "@/assets/pointing-finger.svg";
import { GridCard } from "@/components/Card"; import { GridCard } from "@/components/Card";
import { Checkbox } from "@/components/Checkbox"; import { Checkbox } from "@/components/Checkbox";
import { useDeviceSettingsStore, useSettingsStore } from "@/hooks/stores"; import { useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications"; import notifications from "@/notifications";
import { SettingsPageHeader } from "@components/SettingsPageheader"; import { SettingsPageHeader } from "@components/SettingsPageheader";
import { FeatureFlag } from "../components/FeatureFlag";
import { SelectMenuBasic } from "../components/SelectMenuBasic";
import { useFeatureFlag } from "../hooks/useFeatureFlag"; import { useFeatureFlag } from "../hooks/useFeatureFlag";
import { cx } from "../cva.config";
import { SettingsItem } from "./devices.$id.settings"; import { SettingsItem } from "./devices.$id.settings";
type ScrollSensitivity = "low" | "default" | "high";
export default function SettingsKeyboardMouseRoute() { export default function SettingsKeyboardMouseRoute() {
const hideCursor = useSettingsStore(state => state.isCursorHidden); const hideCursor = useSettingsStore(state => state.isCursorHidden);
const setHideCursor = useSettingsStore(state => state.setCursorVisibility); const setHideCursor = useSettingsStore(state => state.setCursorVisibility);
@ -25,11 +22,6 @@ export default function SettingsKeyboardMouseRoute() {
const mouseMode = useSettingsStore(state => state.mouseMode); const mouseMode = useSettingsStore(state => state.mouseMode);
const setMouseMode = useSettingsStore(state => state.setMouseMode); const setMouseMode = useSettingsStore(state => state.setMouseMode);
const scrollSensitivity = useDeviceSettingsStore(state => state.scrollSensitivity);
const setScrollSensitivity = useDeviceSettingsStore(
state => state.setScrollSensitivity,
);
const { isEnabled: isScrollSensitivityEnabled } = useFeatureFlag("0.3.8"); const { isEnabled: isScrollSensitivityEnabled } = useFeatureFlag("0.3.8");
const [jiggler, setJiggler] = useState(false); const [jiggler, setJiggler] = useState(false);
@ -41,14 +33,7 @@ export default function SettingsKeyboardMouseRoute() {
if ("error" in resp) return; if ("error" in resp) return;
setJiggler(resp.result as boolean); setJiggler(resp.result as boolean);
}); });
}, [isScrollSensitivityEnabled, send]);
if (isScrollSensitivityEnabled) {
send("getScrollSensitivity", {}, resp => {
if ("error" in resp) return;
setScrollSensitivity(resp.result as ScrollSensitivity);
});
}
}, [isScrollSensitivityEnabled, send, setScrollSensitivity]);
const handleJigglerChange = (enabled: boolean) => { const handleJigglerChange = (enabled: boolean) => {
send("setJigglerState", { enabled }, resp => { send("setJigglerState", { enabled }, resp => {
@ -62,22 +47,6 @@ export default function SettingsKeyboardMouseRoute() {
}); });
}; };
const onScrollSensitivityChange = useCallback(
(e: React.ChangeEvent<HTMLSelectElement>) => {
const sensitivity = e.target.value as ScrollSensitivity;
send("setScrollSensitivity", { sensitivity }, resp => {
if ("error" in resp) {
notifications.error(
`Failed to set scroll sensitivity: ${resp.error.data || "Unknown error"}`,
);
}
notifications.success("Scroll sensitivity set successfully");
setScrollSensitivity(sensitivity);
});
},
[send, setScrollSensitivity],
);
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<SettingsPageHeader <SettingsPageHeader
@ -96,28 +65,6 @@ export default function SettingsKeyboardMouseRoute() {
/> />
</SettingsItem> </SettingsItem>
<FeatureFlag minAppVersion="0.3.8" name="Scroll Sensitivity">
<SettingsItem
title="Scroll Sensitivity"
description="Adjust the scroll sensitivity"
>
<SelectMenuBasic
size="SM"
label=""
fullWidth
value={scrollSensitivity}
onChange={onScrollSensitivityChange}
options={
[
{ label: "Low", value: "low" },
{ label: "Default", value: "default" },
{ label: "High", value: "high" },
] as { label: string; value: ScrollSensitivity }[]
}
/>
</SettingsItem>
</FeatureFlag>
<SettingsItem <SettingsItem
title="Jiggler" title="Jiggler"
description="Simulate movement of a computer mouse. Prevents sleep mode, standby mode or the screensaver from activating" description="Simulate movement of a computer mouse. Prevents sleep mode, standby mode or the screensaver from activating"
@ -131,17 +78,19 @@ export default function SettingsKeyboardMouseRoute() {
<SettingsItem title="Modes" description="Choose the mouse input mode" /> <SettingsItem title="Modes" description="Choose the mouse input mode" />
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<button <button
className="block group grow" className="group block grow"
onClick={() => { setMouseMode("absolute"); }} onClick={() => {
setMouseMode("absolute");
}}
> >
<GridCard> <GridCard>
<div className="flex items-center px-4 py-3 group gap-x-4"> <div className="group flex w-full items-center gap-x-4 px-4 py-3">
<img <img
className="w-6 shrink-0 dark:invert" className="w-6 shrink-0 dark:invert"
src={PointingFinger} src={PointingFinger}
alt="Finger touching a screen" alt="Finger touching a screen"
/> />
<div className="flex items-center justify-between grow"> <div className="flex grow items-center justify-between">
<div className="text-left"> <div className="text-left">
<h3 className="text-sm font-semibold text-black dark:text-white"> <h3 className="text-sm font-semibold text-black dark:text-white">
Absolute Absolute
@ -150,32 +99,44 @@ export default function SettingsKeyboardMouseRoute() {
Most convenient Most convenient
</p> </p>
</div> </div>
{mouseMode === "absolute" && ( <CheckCircleIcon
<CheckCircleIcon className="w-4 h-4 text-blue-700 dark:text-blue-500" /> className={cx(
)} "h-4 w-4 text-blue-700 opacity-0 transition dark:text-blue-500",
{ "opacity-100": mouseMode === "absolute" },
)}
/>
</div> </div>
</div> </div>
</GridCard> </GridCard>
</button> </button>
<button <button
className="block group grow" className="group block grow"
onClick={() => { setMouseMode("relative"); }} onClick={() => {
setMouseMode("relative");
}}
> >
<GridCard> <GridCard>
<div className="flex items-center px-4 py-3 gap-x-4"> <div className="flex w-full items-center gap-x-4 px-4 py-3">
<img className="w-6 shrink-0 dark:invert" src={MouseIcon} alt="Mouse icon" /> <img
<div className="flex items-center justify-between grow"> className="w-6 shrink-0 dark:invert"
src={MouseIcon}
alt="Mouse icon"
/>
<div className="flex grow items-center justify-between">
<div className="text-left"> <div className="text-left">
<h3 className="text-sm font-semibold text-black dark:text-white"> <h3 className="text-sm font-semibold text-black dark:text-white">
Relative Relative
</h3> </h3>
<p className="text-xs leading-none text-slate-800 dark:text-slate-300"> <p className="text-xs leading-none text-slate-800 dark:text-slate-300">
Most Compatible (Beta) Most Compatible
</p> </p>
</div> </div>
{mouseMode === "relative" && ( <CheckCircleIcon
<CheckCircleIcon className="w-4 h-4 text-blue-700 dark:text-blue-500" /> className={cx(
)} "h-4 w-4 text-blue-700 opacity-0 transition dark:text-blue-500",
{ "opacity-100": mouseMode === "relative" },
)}
/>
</div> </div>
</div> </div>
</GridCard> </GridCard>

View File

@ -18,11 +18,9 @@ import useWebSocket from "react-use-websocket";
import { cx } from "@/cva.config"; import { cx } from "@/cva.config";
import { import {
DeviceSettingsState,
HidState, HidState,
NetworkState, NetworkState,
UpdateState, UpdateState,
useDeviceSettingsStore,
useDeviceStore, useDeviceStore,
useHidStore, useHidStore,
useMountMediaStore, useMountMediaStore,
@ -714,21 +712,6 @@ export default function KvmIdRoute() {
}); });
}, [appVersion, send, setAppVersion, setSystemVersion]); }, [appVersion, send, setAppVersion, setSystemVersion]);
const setScrollSensitivity = useDeviceSettingsStore(
state => state.setScrollSensitivity,
);
// Initialize device settings
useEffect(
function initializeDeviceSettings() {
send("getScrollSensitivity", {}, resp => {
if ("error" in resp) return;
setScrollSensitivity(resp.result as DeviceSettingsState["scrollSensitivity"]);
});
},
[send, setScrollSensitivity],
);
const ConnectionStatusElement = useMemo(() => { const ConnectionStatusElement = useMemo(() => {
const hasConnectionFailed = const hasConnectionFailed =
connectionFailed || ["failed", "closed"].includes(peerConnectionState || ""); connectionFailed || ["failed", "closed"].includes(peerConnectionState || "");