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
}
var currentScrollSensitivity string = "default"
func rpcGetScrollSensitivity() (string, error) {
return currentScrollSensitivity, nil
}
func rpcSetScrollSensitivity(sensitivity string) error {
currentScrollSensitivity = sensitivity
return nil
}
func getKeyboardMacros() (interface{}, error) {
macros := make([]KeyboardMacro, len(config.KeyboardMacros))
copy(macros, config.KeyboardMacros)
@ -1053,8 +1042,6 @@ var rpcHandlers = map[string]RPCHandler{
"setUsbDevices": {Func: rpcSetUsbDevices, Params: []string{"devices"}},
"setUsbDeviceState": {Func: rpcSetUsbDeviceState, Params: []string{"device", "enabled"}},
"setCloudUrl": {Func: rpcSetCloudUrl, Params: []string{"apiUrl", "appUrl"}},
"getScrollSensitivity": {Func: rpcGetScrollSensitivity},
"setScrollSensitivity": {Func: rpcSetScrollSensitivity, Params: []string{"sensitivity"}},
"getKeyboardMacros": {Func: getKeyboardMacros},
"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 {
useDeviceSettingsStore,
useHidStore,
useMouseStore,
useRTCStore,
@ -61,7 +60,6 @@ export default function WebRTCVideo() {
useHidStore();
// Misc states and hooks
const [blockWheelEvent, setBlockWheelEvent] = useState(false);
const disableVideoFocusTrap = useUiStore(state => state.disableVideoFocusTrap);
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(
(e: WheelEvent) => {
if (blockWheelEvent) return;
// Determine if the wheel event is an accel scroll value
const isAccel = Math.abs(e.deltaY) >= 100;
@ -266,7 +255,7 @@ export default function WebRTCVideo() {
const accelScrollValue = e.deltaY / 100;
// 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
const scrollValue = isAccel ? accelScrollValue : noAccelScrollValue;
@ -277,22 +266,9 @@ export default function WebRTCVideo() {
// Invert the clamped scroll value to match expected behavior
const invertedScrollValue = -clampedScrollValue;
send("wheelReport", { wheelY : invertedScrollValue });
// Apply blocking delay
setBlockWheelEvent(true);
setTimeout(() => setBlockWheelEvent(false), blockDelay);
send("wheelReport", { wheelY: invertedScrollValue });
},
[
blockDelay,
blockWheelEvent,
clampMax,
clampMin,
mouseSensitivity,
send,
trackpadSensitivity,
trackpadThreshold,
],
[send],
);
const resetMousePosition = useCallback(() => {
@ -351,11 +327,7 @@ export default function WebRTCVideo() {
// 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
// to properly release the state of that modifier.
.filter(
modifier =>
altKey ||
(modifier !== modifiers["AltLeft"]),
)
.filter(modifier => altKey || modifier !== modifiers["AltLeft"])
// Meta: Keep if Meta is pressed or if the key isn't a Meta key
// Example: If metaKey is true, keep all modifiers
// If metaKey is false, filter out 0x08 (MetaLeft) and 0x80 (MetaRight)
@ -716,7 +688,7 @@ export default function WebRTCVideo() {
disablePictureInPicture
controlsList="nofullscreen"
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,
"opacity-0":
@ -732,7 +704,7 @@ export default function WebRTCVideo() {
{peerConnection?.connectionState == "connected" && (
<div
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">
<LoadingVideoOverlay show={isVideoLoading} />

View File

@ -321,8 +321,7 @@ export const useSettingsStore = create(
setDeveloperMode: enabled => set({ developerMode: enabled }),
displayRotation: "270",
setDisplayRotation: (rotation: string) =>
set({ displayRotation: rotation }),
setDisplayRotation: (rotation: string) => set({ displayRotation: rotation }),
backlightSettings: {
max_brightness: 100,
@ -350,67 +349,6 @@ export interface DeviceSettingsState {
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 {
source: "WebRTC" | "HTTP" | "Storage" | null;
mode: "CDROM" | "Disk" | null;

View File

@ -1,23 +1,20 @@
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 PointingFinger from "@/assets/pointing-finger.svg";
import { GridCard } from "@/components/Card";
import { Checkbox } from "@/components/Checkbox";
import { useDeviceSettingsStore, useSettingsStore } from "@/hooks/stores";
import { useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { FeatureFlag } from "../components/FeatureFlag";
import { SelectMenuBasic } from "../components/SelectMenuBasic";
import { useFeatureFlag } from "../hooks/useFeatureFlag";
import { cx } from "../cva.config";
import { SettingsItem } from "./devices.$id.settings";
type ScrollSensitivity = "low" | "default" | "high";
export default function SettingsKeyboardMouseRoute() {
const hideCursor = useSettingsStore(state => state.isCursorHidden);
const setHideCursor = useSettingsStore(state => state.setCursorVisibility);
@ -25,11 +22,6 @@ export default function SettingsKeyboardMouseRoute() {
const mouseMode = useSettingsStore(state => state.mouseMode);
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 [jiggler, setJiggler] = useState(false);
@ -41,14 +33,7 @@ export default function SettingsKeyboardMouseRoute() {
if ("error" in resp) return;
setJiggler(resp.result as boolean);
});
if (isScrollSensitivityEnabled) {
send("getScrollSensitivity", {}, resp => {
if ("error" in resp) return;
setScrollSensitivity(resp.result as ScrollSensitivity);
});
}
}, [isScrollSensitivityEnabled, send, setScrollSensitivity]);
}, [isScrollSensitivityEnabled, send]);
const handleJigglerChange = (enabled: boolean) => {
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 (
<div className="space-y-4">
<SettingsPageHeader
@ -96,28 +65,6 @@ export default function SettingsKeyboardMouseRoute() {
/>
</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
title="Jiggler"
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" />
<div className="flex items-center gap-4">
<button
className="block group grow"
onClick={() => { setMouseMode("absolute"); }}
className="group block grow"
onClick={() => {
setMouseMode("absolute");
}}
>
<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
className="w-6 shrink-0 dark:invert"
src={PointingFinger}
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">
<h3 className="text-sm font-semibold text-black dark:text-white">
Absolute
@ -150,32 +99,44 @@ export default function SettingsKeyboardMouseRoute() {
Most convenient
</p>
</div>
{mouseMode === "absolute" && (
<CheckCircleIcon className="w-4 h-4 text-blue-700 dark:text-blue-500" />
)}
<CheckCircleIcon
className={cx(
"h-4 w-4 text-blue-700 opacity-0 transition dark:text-blue-500",
{ "opacity-100": mouseMode === "absolute" },
)}
/>
</div>
</div>
</GridCard>
</button>
<button
className="block group grow"
onClick={() => { setMouseMode("relative"); }}
className="group block grow"
onClick={() => {
setMouseMode("relative");
}}
>
<GridCard>
<div className="flex items-center px-4 py-3 gap-x-4">
<img className="w-6 shrink-0 dark:invert" src={MouseIcon} alt="Mouse icon" />
<div className="flex items-center justify-between grow">
<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"
/>
<div className="flex grow items-center justify-between">
<div className="text-left">
<h3 className="text-sm font-semibold text-black dark:text-white">
Relative
</h3>
<p className="text-xs leading-none text-slate-800 dark:text-slate-300">
Most Compatible (Beta)
Most Compatible
</p>
</div>
{mouseMode === "relative" && (
<CheckCircleIcon className="w-4 h-4 text-blue-700 dark:text-blue-500" />
)}
<CheckCircleIcon
className={cx(
"h-4 w-4 text-blue-700 opacity-0 transition dark:text-blue-500",
{ "opacity-100": mouseMode === "relative" },
)}
/>
</div>
</div>
</GridCard>

View File

@ -18,11 +18,9 @@ import useWebSocket from "react-use-websocket";
import { cx } from "@/cva.config";
import {
DeviceSettingsState,
HidState,
NetworkState,
UpdateState,
useDeviceSettingsStore,
useDeviceStore,
useHidStore,
useMountMediaStore,
@ -714,21 +712,6 @@ export default function KvmIdRoute() {
});
}, [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 hasConnectionFailed =
connectionFailed || ["failed", "closed"].includes(peerConnectionState || "");