Skip to content

Commit 1f7c5c9

Browse files
authored
feat(ui): Add Ctrl+Alt+Del to the action bar (#498)
Since this is the sort of thing we do all the time, make it one-click away
1 parent 55d7f22 commit 1f7c5c9

File tree

4 files changed

+87
-3
lines changed

4 files changed

+87
-3
lines changed

ui/src/components/ActionBar.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { MdOutlineContentPasteGo } from "react-icons/md";
22
import { LuCable, LuHardDrive, LuMaximize, LuSettings, LuSignal } from "react-icons/lu";
3-
import { FaKeyboard } from "react-icons/fa6";
3+
import { FaKeyboard, FaLock} from "react-icons/fa6";
44
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
55
import { Fragment, useCallback, useRef } from "react";
66
import { CommandLineIcon } from "@heroicons/react/20/solid";
@@ -19,6 +19,8 @@ import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index";
1919
import MountPopopover from "@/components/popovers/MountPopover";
2020
import ExtensionPopover from "@/components/popovers/ExtensionPopover";
2121
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
22+
import useKeyboard from "@/hooks/useKeyboard";
23+
import { keys, modifiers } from "@/keyboardMappings";
2224

2325
export default function Actionbar({
2426
requestFullscreen,
@@ -56,6 +58,8 @@ export default function Actionbar({
5658
[setDisableFocusTrap],
5759
);
5860

61+
const { sendKeyboardEvent, resetKeyboardState } = useKeyboard();
62+
5963
return (
6064
<Container className="border-b border-b-slate-800/20 bg-white dark:border-b-slate-300/20 dark:bg-slate-900">
6165
<div
@@ -262,7 +266,23 @@ export default function Actionbar({
262266
}}
263267
/>
264268
</div>
265-
269+
{useSettingsStore().actionBarCtrlAltDel && (
270+
<div className="hidden lg:block">
271+
<Button
272+
size="XS"
273+
theme="light"
274+
text="Ctrl + Alt + Del"
275+
LeadingIcon={FaLock}
276+
onClick={() => {
277+
sendKeyboardEvent(
278+
[keys["Delete"]],
279+
[modifiers["ControlLeft"], modifiers["AltLeft"]],
280+
);
281+
setTimeout(resetKeyboardState, 100);
282+
}}
283+
/>
284+
</div>
285+
)}
266286
<div>
267287
<Button
268288
size="XS"

ui/src/hooks/stores.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ interface SettingsState {
308308
keyboardLayout: string;
309309
setKeyboardLayout: (layout: string) => void;
310310

311+
actionBarCtrlAltDel: boolean;
312+
setActionBarCtrlAltDel: (enabled: boolean) => void;
313+
311314
keyboardLedSync: KeyboardLedSync;
312315
setKeyboardLedSync: (sync: KeyboardLedSync) => void;
313316

@@ -345,6 +348,9 @@ export const useSettingsStore = create(
345348
keyboardLayout: "en-US",
346349
setKeyboardLayout: layout => set({ keyboardLayout: layout }),
347350

351+
actionBarCtrlAltDel: false,
352+
setActionBarCtrlAltDel: enabled => set({ actionBarCtrlAltDel: enabled }),
353+
348354
keyboardLedSync: "auto",
349355
setKeyboardLedSync: sync => set({ keyboardLedSync: sync }),
350356

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { SettingsItem } from "./devices.$id.settings";
2+
3+
import { Checkbox } from "@/components/Checkbox";
4+
import { SettingsPageHeader } from "@/components/SettingsPageheader";
5+
6+
import { useSettingsStore } from "@/hooks/stores";
7+
8+
export default function SettingsCtrlAltDelRoute() {
9+
const enableCtrlAltDel = useSettingsStore(state => state.actionBarCtrlAltDel);
10+
const setEnableCtrlAltDel = useSettingsStore(state => state.setActionBarCtrlAltDel);
11+
12+
return (
13+
<div className="space-y-4">
14+
<SettingsPageHeader
15+
title="Action Bar"
16+
description="Customize the action bar of your JetKVM interface"
17+
/>
18+
<div className="space-y-4">
19+
<SettingsItem title="Enable Ctrl-Alt-Del" description="Enable the Ctrl-Alt-Del key on the virtual keyboard">
20+
<Checkbox
21+
checked={enableCtrlAltDel}
22+
onChange={e => setEnableCtrlAltDel(e.target.checked)}
23+
/>
24+
</SettingsItem>
25+
</div>
26+
</div>
27+
);
28+
}

ui/src/routes/devices.$id.settings.hardware.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
import { useEffect } from "react";
1+
import { useCallback, useEffect, useState } from "react";
22

33
import { SettingsPageHeader } from "@components/SettingsPageheader";
44
import { SettingsItem } from "@routes/devices.$id.settings";
55
import { BacklightSettings, useSettingsStore } from "@/hooks/stores";
66
import { useJsonRpc } from "@/hooks/useJsonRpc";
7+
import Checkbox from "@components/Checkbox";
78
import { SelectMenuBasic } from "@components/SelectMenuBasic";
89
import { UsbDeviceSetting } from "@components/UsbDeviceSetting";
910

1011
import notifications from "../notifications";
1112
import { UsbInfoSetting } from "../components/UsbInfoSetting";
1213
import { FeatureFlag } from "../components/FeatureFlag";
1314

15+
export interface ActionBarConfig {
16+
ctrlAltDel: boolean;
17+
}
18+
19+
const defaultActionBarConfig: ActionBarConfig = {
20+
ctrlAltDel: false,
21+
};
22+
1423
export default function SettingsHardwareRoute() {
1524
const [send] = useJsonRpc();
1625
const settings = useSettingsStore();
@@ -71,6 +80,18 @@ export default function SettingsHardwareRoute() {
7180
});
7281
}, [send, setBacklightSettings]);
7382

83+
const [actionBarConfig, setActionBarConfig] = useState<ActionBarConfig>(defaultActionBarConfig);
84+
85+
const onActionBarItemChange = useCallback(
86+
(key: keyof ActionBarConfig) => (e: React.ChangeEvent<HTMLInputElement>) => {
87+
setActionBarConfig(prev => ({
88+
...prev,
89+
[key]: e.target.checked,
90+
}));
91+
},
92+
[],
93+
);
94+
7495
return (
7596
<div className="space-y-4">
7697
<SettingsPageHeader
@@ -116,6 +137,15 @@ export default function SettingsHardwareRoute() {
116137
}}
117138
/>
118139
</SettingsItem>
140+
<SettingsItem
141+
title="Enable Ctrl+Alt+Del Action Bar"
142+
description="Enable or disable the action bar action for sending a Ctrl+Alt+Del to the host"
143+
>
144+
<Checkbox
145+
checked={actionBarConfig.ctrlAltDel}
146+
onChange={onActionBarItemChange("ctrlAltDel")}
147+
/>
148+
</SettingsItem>
119149
{settings.backlightSettings.max_brightness != 0 && (
120150
<>
121151
<SettingsItem

0 commit comments

Comments
 (0)