Compare commits

...

2 Commits

Author SHA1 Message Date
JackTheRooster 546bca4af1 added link to lookup usb device ids 2025-02-17 22:53:23 -06:00
JackTheRooster 23771e7bb6 added preconfigured options for USB Emulation 2025-02-17 22:29:04 -06:00
2 changed files with 114 additions and 10 deletions

View File

@ -7,6 +7,7 @@ import Modal from "@components/Modal";
import { InputFieldWithLabel } from "./InputField"; import { InputFieldWithLabel } from "./InputField";
import { useJsonRpc } from "@/hooks/useJsonRpc"; import { useJsonRpc } from "@/hooks/useJsonRpc";
import { useUsbConfigModalStore } from "@/hooks/stores"; import { useUsbConfigModalStore } from "@/hooks/stores";
import ExtLink from "@components/ExtLink";
export interface UsbConfigState { export interface UsbConfigState {
vendor_id: string; vendor_id: string;
@ -135,18 +136,26 @@ function UpdateUsbConfigModal({
Set custom USB parameters to control how the USB device is emulated. Set custom USB parameters to control how the USB device is emulated.
The device will rebind once the parameters are updated. The device will rebind once the parameters are updated.
</p> </p>
<div className="flex justify-start mt-4 text-xs text-slate-500 dark:text-slate-400">
<ExtLink
href={`https://the-sz.com/products/usbid/index.php?v=${usbConfigState.vendor_id}&p=${usbConfigState.product_id}`}
className="hover:underline"
>
Look up USB Device IDs
</ExtLink>
</div>
</div> </div>
<InputFieldWithLabel <InputFieldWithLabel
required required
label="Vendor ID" label="Vendor ID"
placeholder="Enter Vendor ID" placeholder="Enter Vendor ID"
pattern="^0[xX][\da-fA-F]{4}$" pattern="^0[xX][\da-fA-F]{4}$"
defaultValue={usbConfigState?.vendor_id} defaultValue={usbConfigState?.vendor_id}
onChange={e => handleUsbVendorIdChange(e.target.value)} onChange={e => handleUsbVendorIdChange(e.target.value)}
/> />
<InputFieldWithLabel <InputFieldWithLabel
required required
label="Product ID" label="Product ID"
placeholder="Enter Product ID" placeholder="Enter Product ID"
pattern="^0[xX][\da-fA-F]{4}$" pattern="^0[xX][\da-fA-F]{4}$"
defaultValue={usbConfigState?.product_id} defaultValue={usbConfigState?.product_id}

View File

@ -74,6 +74,63 @@ const edids = [
}, },
]; ];
const defaultUsbConfig =
JSON.stringify({
vendor_id: "0x1d6b",
product_id: "0x0104",
serial_number: "",
manufacturer: "JetKVM",
product: "JetKVM USB Emulation Device",
})
const usbConfigs = [
{
value: defaultUsbConfig,
label: "JetKVM Default",
},
{
value: JSON.stringify({
vendor_id: "0x046d",
product_id: "0xc52b",
serial_number: [generateNumber(1,9), generateHex(7,7), 0, 1].join("&"),
manufacturer: "Logitech (x64)",
product: "Logitech USB Input Device",
}),
label: "Logitech Universal Adapter",
},
{
value: JSON.stringify({
vendor_id: "0x045e",
product_id: "0x005f",
serial_number: [generateNumber(1,9), generateHex(7,7), 0, 1].join("&"),
manufacturer: "Microsoft",
product: "Wireless MultiMedia Keyboard",
}),
label: "Microsoft Wireless MultiMedia Keyboard",
},
{
value: JSON.stringify({
vendor_id: "0x413c",
product_id: "0x2011",
serial_number: [generateNumber(1,9), generateHex(7,7), 0, 1].join("&"),
manufacturer: "Dell Inc.",
product: "Multimedia Pro Keyboard",
}),
label: "Dell Multimedia Pro Keyboard",
}
];
function generateNumber(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function generateHex(min: number, max: number) {
const len = generateNumber(min, max);
const n = (Math.random() * 0xfffff * 1000000).toString(16);
return n.slice(0, len);
}
export default function SettingsSidebar() { export default function SettingsSidebar() {
const setSidebarView = useUiStore(state => state.setSidebarView); const setSidebarView = useUiStore(state => state.setSidebarView);
const settings = useSettingsStore(); const settings = useSettingsStore();
@ -84,6 +141,7 @@ export default function SettingsSidebar() {
const [jiggler, setJiggler] = useState(false); const [jiggler, setJiggler] = useState(false);
const [edid, setEdid] = useState<string | null>(null); const [edid, setEdid] = useState<string | null>(null);
const [customEdidValue, setCustomEdidValue] = useState<string | null>(null); const [customEdidValue, setCustomEdidValue] = useState<string | null>(null);
const [usbConfigJson, setUsbConfigJson] = useState("");
const [isAdopted, setAdopted] = useState(false); const [isAdopted, setAdopted] = useState(false);
const [deviceId, setDeviceId] = useState<string | null>(null); const [deviceId, setDeviceId] = useState<string | null>(null);
@ -183,6 +241,21 @@ export default function SettingsSidebar() {
}); });
}; };
const handleUsbConfigChange = (jsonString: string) => {
const usbConfig = JSON.parse(jsonString);
send("setUsbConfig", { usbConfig }, resp => {
if ("error" in resp) {
notifications.error(
`Failed to set usb config: ${resp.error.data || "Unknown error"}`,
);
return;
}
setUsbConfigJson(jsonString);
notifications.success(`USB Config set to ${usbConfig.product}`);
console.info(`usbConfigJson set to: ${usbConfigJson}`)
});
};
const handleJigglerChange = (enabled: boolean) => { const handleJigglerChange = (enabled: boolean) => {
send("setJigglerState", { enabled }, resp => { send("setJigglerState", { enabled }, resp => {
if ("error" in resp) { if ("error" in resp) {
@ -860,8 +933,30 @@ export default function SettingsSidebar() {
</SettingsItem> </SettingsItem>
{settings.developerMode && ( {settings.developerMode && (
<SettingsItem <SettingsItem
title="USB Configuration" title="Set USB Device Emulation"
description="Set the USB Descriptors for the JetKVM" description="Select a Preconfigured USB Device"
>
<SelectMenuBasic
size="SM"
label=""
fullWidth
value={usbConfigJson}
onChange={e => {
if (e.target.value === "custom") {
setUsbConfigJson("custom")
// If set to custom, show the USB Config button
} else {
handleUsbConfigChange(e.target.value as string);
}
}}
options={[...usbConfigs, { value: "custom", label: "Custom" }]}
/>
</SettingsItem>
)}
{usbConfigJson == "custom" && (
<SettingsItem
title="USB Config"
description="Set Custom USB Descriptors"
> >
<Button <Button
size="SM" size="SM"