now using gadget last input time to determine if jiggler can be activated

added UI elements to set jiggler config
This commit is contained in:
JackTheRooster 2025-03-26 23:51:45 -05:00
parent 34786647c0
commit c338533029
4 changed files with 56 additions and 44 deletions

View File

@ -49,8 +49,8 @@ var defaultConfig = &Config{
DisplayOffAfterSec: 1800, // 30 minutes
JigglerConfig: &JigglerConfig{
InactivityLimitSeconds: 20,
JitterPercentage: 0.0,
ScheduleCronTab: "*/5 * * * * *",
JitterPercentage: 0,
ScheduleCronTab: "*/20 * * * * *",
},
TLSMode: "",
UsbConfig: &usbgadget.Config{

View File

@ -1,18 +1,18 @@
package kvm
import (
"fmt"
"github.com/go-co-op/gocron/v2"
"math/rand"
"time"
)
type JigglerConfig struct {
InactivityLimitSeconds float64 `json:"inactivity_limit_seconds"`
JitterPercentage float64 `json:"jitter_percentage"`
InactivityLimitSeconds int `json:"inactivity_limit_seconds"`
JitterPercentage int `json:"jitter_percentage"`
ScheduleCronTab string `json:"schedule_cron_tab"`
}
var lastUserInput = time.Now()
var jigglerEnabled = false
var jobDelta time.Duration = 0
var scheduler gocron.Scheduler = nil
@ -28,18 +28,22 @@ func rpcGetJigglerConfig() (JigglerConfig, error) {
return *config.JigglerConfig, nil
}
func rpcSetJigglerConfig(jigglerConfig JigglerConfig) {
func rpcSetJigglerConfig(jigglerConfig JigglerConfig) error {
logger.Infof("[jsonrpc.go:rpcSetJigglerConfig] jigglerConfig: %v, %v, %v", jigglerConfig.InactivityLimitSeconds, jigglerConfig.JitterPercentage, jigglerConfig.ScheduleCronTab)
config.JigglerConfig = &jigglerConfig
err := removeExistingCrobJobs(scheduler)
if err != nil {
logger.Errorf("Error removing cron jobs from scheduler %v", err)
return
return fmt.Errorf("error removing cron jobs from scheduler %v", err)
}
err = runJigglerCronTab()
if err != nil {
logger.Errorf("Error scheduling jiggler crontab: %v", err)
return
return fmt.Errorf("error scheduling jiggler crontab: %v", err)
}
err = SaveConfig()
if err != nil {
return fmt.Errorf("failed to save config: %w", err)
}
return nil
}
func removeExistingCrobJobs(s gocron.Scheduler) error {
@ -100,7 +104,7 @@ func runJiggler() {
time.Sleep(jitter)
}
inactivitySeconds := config.JigglerConfig.InactivityLimitSeconds
if time.Since(lastUserInput) > time.Duration(inactivitySeconds)*time.Second {
if time.Since(gadget.GetLastUserInputTime()) > time.Duration(inactivitySeconds)*time.Second {
//TODO: change to rel mouse
err := rpcAbsMouseReport(1, 1, 0)
if err != nil {
@ -124,6 +128,6 @@ func calculateJobDelta(s gocron.Scheduler) (time.Duration, error) {
}
func calculateJitterDuration(delta time.Duration) time.Duration {
jitter := rand.Float64() * config.JigglerConfig.JitterPercentage * delta.Seconds()
jitter := rand.Float64() * float64(config.JigglerConfig.JitterPercentage) / 100 * delta.Seconds()
return time.Duration(jitter * float64(time.Second))
}

View File

@ -37,19 +37,19 @@ const jigglerCrontabConfigs = [
const jigglerJitterConfigs = [
{
label: "No Jitter",
value: "0.0",
value: "0",
},
{
label: "10%",
value: ".1",
value: "20",
},
{
label: "25%",
value: ".25",
value: "25",
},
{
label: "50%",
value: ".5",
value: "50",
},
];
@ -75,13 +75,12 @@ const jigglerInactivityConfigs = [
export function JigglerSetting() {
const [send] = useJsonRpc();
const [loading, setLoading] = useState(false);
const [inactivityLimitSeconds, setInactivityLimitSeconds] = useState("");
const [jitterPercentage, setJitterPercentage] = useState("");
const [scheduleCronTab, setScheduleCronTab] = useState("");
const [jigglerConfigState, setJigglerConfigState] = useState<JigglerConfig>({
inactivity_limit_seconds: 20.0,
jitter_percentage: 0.0,
inactivity_limit_seconds: 20,
jitter_percentage: 0,
schedule_cron_tab: "*/20 * * * * *"
});
@ -90,28 +89,32 @@ export function JigglerSetting() {
if ("error" in resp) return;
const result = resp.result as JigglerConfig;
setJigglerConfigState(result);
setInactivityLimitSeconds(String(result.inactivity_limit_seconds))
setJitterPercentage(String(result.jitter_percentage))
setScheduleCronTab(result.schedule_cron_tab)
const jitterPercentage = jigglerJitterConfigs.map(u => u.value).includes(result.jitter_percentage.toString())
? result.jitter_percentage.toString()
: "custom";
setJitterPercentage(jitterPercentage)
const scheduleCronTab = jigglerCrontabConfigs.map(u => u.value).includes(result.schedule_cron_tab)
? result.schedule_cron_tab
: "custom";
setScheduleCronTab(scheduleCronTab)
});
}, [send, setInactivityLimitSeconds]);
}, [send]);
useEffect(() => {
syncJigglerConfig()
}, [send, syncJigglerConfig]);
const handleJigglerInactivityLimitSecondsChange = (value: string) => {
setInactivityLimitSeconds(value)
setJigglerConfigState({ ...jigglerConfigState, inactivity_limit_seconds: Number(value) });
};
const handleJigglerJitterPercentageChange = (value: string) => {
setJitterPercentage(value)
setJigglerConfigState({ ...jigglerConfigState, jitter_percentage: Number(value) });
};
const handleJigglerScheduleCronTabChange = (value: string) => {
setScheduleCronTab(value)
setJigglerConfigState({ ...jigglerConfigState, schedule_cron_tab: value });
};
@ -146,23 +149,23 @@ export function JigglerSetting() {
value={scheduleCronTab}
fullWidth
onChange={e => {
if (e.target.value === "custom") {
setScheduleCronTab(e.target.value);
} else {
handleJigglerScheduleCronTabChange(e.target.value)
if (e.target.value != "custom") {
handleJigglerScheduleCronTabChange(e.target.value);
}
}}
options={[...jigglerCrontabConfigs, {value: "custom", label: "Custom"}]}
/>
{jitterPercentage === "custom" && (
{scheduleCronTab === "custom" && (
<InputFieldWithLabel
required
label="Jiggler Crontab"
placeholder="Enter Cron Tab"
value={scheduleCronTab}
placeholder="*/20 * * * * *"
onChange={e => handleJigglerScheduleCronTabChange(e.target.value)}
/>
)}
</div>
<div className="grid grid-cols-2 gap-4">
<SelectMenuBasic
size="SM"
label="Jitter Percentage"
@ -170,9 +173,8 @@ export function JigglerSetting() {
value={jitterPercentage}
fullWidth
onChange={e => {
if (e.target.value === "custom") {
setJitterPercentage(e.target.value);
} else {
if (e.target.value != "custom") {
handleJigglerJitterPercentageChange(e.target.value)
}
}}
@ -182,15 +184,20 @@ export function JigglerSetting() {
<InputFieldWithLabel
required
label="Jitter Percentage"
placeholder="0.0"
placeholder="30"
type="number"
min="1"
max="100"
onChange={e => handleJigglerJitterPercentageChange(e.target.value)}
/>
)}
</div>
<div className="grid grid-cols-2 gap-4">
<SelectMenuBasic
size="SM"
label="Inactivity Limit Seconds"
className="max-w-[192px]"
value={inactivityLimitSeconds}
value={jigglerConfigState.inactivity_limit_seconds}
fullWidth
onChange={e => {
handleJigglerInactivityLimitSecondsChange(e.target.value);

View File

@ -9,14 +9,15 @@ import { useDeviceSettingsStore, useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import notifications from "@/notifications";
import { SettingsPageHeader } from "@components/SettingsPageheader";
import { JigglerSetting } from "@components/JigglerSetting";
import { SettingsSectionHeader } from "@components/SettingsSectionHeader";
import { FeatureFlag } from "../components/FeatureFlag";
import { SelectMenuBasic } from "../components/SelectMenuBasic";
import { useFeatureFlag } from "../hooks/useFeatureFlag";
import { SettingsItem } from "./devices.$id.settings";
import { JigglerSetting } from "@components/JigglerSetting";
import { SettingsSectionHeader } from "@components/SettingsSectionHeader";
type ScrollSensitivity = "low" | "default" | "high";