import { PrintableShellCommand } from "printable-shell-command"; import { type Device, type DeviceInfo, type Display, type DisplayGroup, deviceFromInfo, type VirtualScreen, } from "./Device"; const BINARY_NAME = "betterdisplaycli"; export interface QuietOption { quiet?: boolean; } export interface DetachOption { detach?: boolean; } export function print( command: PrintableShellCommand, printOptions?: Parameters[0], quietOptions?: QuietOption, ): PrintableShellCommand { if (!quietOptions?.quiet) { command.print(printOptions); } return command; } export async function shellOutSilentOrDetach( command: PrintableShellCommand, options?: DetachOption, ): Promise { if (options?.detach) { command.spawnDetached(); } else { await command.shellOut({ print: false }); } } type GetDeviceOptions = { ignoreDisplayGroups?: true; } & QuietOption; async function getDeviceInfos( printable_shell_command: PrintableShellCommand, options?: GetDeviceOptions, ): Promise { const jsonStream = await print( printable_shell_command, { argumentLineWrapping: "inline" }, options, ) .stdout() .text(); const deviceInfos: DeviceInfo[] = JSON.parse(`[${jsonStream}]`); return deviceInfos .map((info) => deviceFromInfo(info)) .filter((device: Device) => { return ( !options?.ignoreDisplayGroups || device.info.deviceType !== "DisplayGroup" ); }) as T[]; } export async function getAllDevices( options?: GetDeviceOptions, ): Promise<(Display | VirtualScreen)[]>; export async function getAllDevices( options?: GetDeviceOptions, ): Promise { const jsonStream = await print( new PrintableShellCommand(BINARY_NAME, [["get", "--identifiers"]]), { argumentLineWrapping: "inline" }, options, ) .stdout() .text(); const deviceInfos: DeviceInfo[] = JSON.parse(`[${jsonStream}]`); return deviceInfos .map((info) => deviceFromInfo(info)) .filter((device: Device) => { return ( !options?.ignoreDisplayGroups || device.info.deviceType !== "DisplayGroup" ); }); } export function getMain( options?: QuietOption, ): Promise { return getDisplayWithSelectorArg("--displayWithMainStatus", { ...options, ignoreDisplayGroups: true, }); } export async function getByName( name: string, options?: GetDeviceOptions, ): Promise; export function getByName( name: string, options?: GetDeviceOptions, ): Promise { return getDisplayWithSelectorArg(`--name=${name}`, options); } export async function tryGetByName( name: string, options?: GetDeviceOptions, ): Promise; export async function tryGetByName( name: string, options?: GetDeviceOptions, ): Promise { const devices = await getAllDevices(options); return devices.filter((device) => device.info.name === name)[0]; } export async function getDisplayWithSelectorArg( arg: "--displayWithMainStatus" | `--name=${string}`, options?: GetDeviceOptions, ): Promise { return ( await getDeviceInfos( new PrintableShellCommand("betterdisplaycli", [ "get", arg, "--identifiers", ]), options, ) )[0]; } export async function connectAllDisplays(options?: QuietOption): Promise { await print( new PrintableShellCommand(BINARY_NAME, [ ["perform", "--connectAllDisplays"], ]), { argumentLineWrapping: "inline" }, options, ).spawnTransparently().success; }