// @effect-diagnostics nodeBuiltinImport:off -- Stable shortcut IDs and unique portal request tokens.// @effect-diagnostics globalTimers:off -- Bounded D-Bus calls and user-consent requests at the native boundary.import * as NodeCrypto from "node:crypto";import { DBusError, Message, MessageFlag, MessageType, Variant, sessionBus, type MessageBus, type MessageLike,} from "dbus-next";import * as Schema from "effect/Schema";import type { SnapShotKeyChord } from "@t3tools/contracts";import { HYPRLAND_CAPTURE_ACTION, portalShortcutTrigger } from "./linuxCaptureSession.ts";export { portalShortcutTrigger } from "./linuxCaptureSession.ts"; const PORTAL = "org.freedesktop.portal.Desktop";const PATH = "/org/freedesktop/portal/desktop";const SHORTCUTS = "org.freedesktop.portal.GlobalShortcuts";const REQUEST = "org.freedesktop.portal.Request";const SESSION = "org.freedesktop.portal.Session";const DBUS = "org.freedesktop.DBus";const string = Schema.decodeUnknownSync(Schema.String);const StringVariant = Schema.Struct({ signature: Schema.Literal("s"), value: Schema.String });const Shortcuts = Schema.Array( Schema.Tuple([ Schema.String, Schema.Struct({ description: Schema.optional(StringVariant), trigger_description: Schema.optional(StringVariant), }), ]),);const decodeShortcuts = Schema.decodeUnknownSync(Shortcuts);const decodeShortcutsResult = Schema.decodeUnknownSync( Schema.Struct({ shortcuts: Schema.Struct({ signature: Schema.Literal("a(sa{sv})"), value: Shortcuts }), }),);const decodeSession = Schema.decodeUnknownSync(Schema.Struct({ session_handle: StringVariant }));const decodeResponse = Schema.decodeUnknownSync( Schema.Tuple([Schema.Int, Schema.Record(Schema.String, Schema.Unknown)]),);const decodeVersion = Schema.decodeUnknownSync( Schema.Struct({ signature: Schema.Literal("u"), value: Schema.Int, }),); export interface PortalShortcutState { readonly shortcutActionRegistered?: boolean; readonly shortcutRegistered: boolean; readonly shortcutPending: boolean; /** Whether retry-shortcut can reopen permissions or start a new session. */ readonly shortcutCanRetry?: boolean; readonly shortcutLabel?: string; readonly shortcutMessage: string | null;} /** Own the portal session, including consent and release; Electron only reports submission. */export class PortalCaptureShortcut { state: PortalShortcutState = { shortcutRegistered: false, shortcutPending: true, shortcutMessage: "Waiting for shortcut permission. Approve the desktop prompt if one appears.", }; readonly ready: Promise<void>; private closed = false; private owner = ""; private namespace = ""; private session = ""; private shortcutId = ""; private version = 0; private pending: { path: string; resolve: (body: unknown) => void } | undefined; private responses = new Map<string, unknown>(); private readonly stopped: Promise<never>; private rejectStopped!: (reason: Error) => void; private readonly onCapture: () => void; private readonly onStateChanged: () => void; private readonly bus: MessageBus; private readonly managedByHyprland: boolean; constructor( appId: string, shortcut: SnapShotKeyChord, onCapture: () => void, onStateChanged: () => void, bus: MessageBus = sessionBus(), managedByHyprland = false, ) { this.onCapture = onCapture; this.onStateChanged = onStateChanged; this.bus = bus; this.managedByHyprland = managedByHyprland; if (managedByHyprland) this.state = { shortcutRegistered: false, shortcutPending: true, shortcutMessage: "Connecting to Hyprland shortcuts…", }; this.stopped = new Promise((_, reject) => { this.rejectStopped = reject; }); void this.stopped.catch(() => undefined); bus.on("error", this.failed); bus.on("message", this.message); this.ready = this.initialize(appId, shortcut).catch(this.failed); } close = () => { if (this.closed) return; this.closed = true; this.rejectStopped(new Error("Capture shortcut registration closed.")); try { if (this.pending) this.closeObject(this.pending.path, REQUEST); if (this.session) this.closeObject(this.session, SESSION); } catch { // A broken bus is already closing its sessions; local cleanup must still run. } this.bus.removeListener("message", this.message); this.responses.clear(); this.bus.disconnect(); }; /** A previously denied binding is changed by the desktop, not by bypassing its decision. */ get hasSession() { return !this.closed && Boolean(this.session); } async configure() { if (this.managedByHyprland) throw new Error("Change the capture binding in your Hyprland config, then save it."); if (!this.hasSession || this.version < 2) throw new Error( "Open your desktop's shortcut settings and allow T3 Code's capture shortcut.", ); await this.call({ destination: this.owner, path: PATH, interface: SHORTCUTS, member: "ConfigureShortcuts", signature: "osa{sv}", body: [this.session, "", {}], }); } private update(state: PortalShortcutState) { if (this.closed) return; this.state = { shortcutCanRetry: !this.managedByHyprland && (!this.hasSession || this.version >= 2), ...state, }; this.onStateChanged(); } private failed = (error: unknown) => { if (this.closed) return; this.update({ shortcutRegistered: false, shortcutPending: false, // This failed session is closing, so retry can register a fresh one. shortcutCanRetry: !this.managedByHyprland, shortcutMessage: this.managedByHyprland ? "Couldn't connect to Hyprland shortcuts. Make sure xdg-desktop-portal-hyprland is running, then restart T3 Code." : error instanceof Error ? error.message : "Could not register the capture shortcut.", }); this.close(); }; private async wait<T>(promise: Promise<T>, timeoutMs = 5_000): Promise<T> { let timer: ReturnType<typeof setTimeout> | undefined; try { return await Promise.race([ promise, this.stopped, new Promise<never>((_, reject) => { timer = setTimeout( () => reject(new Error("Shortcut permission request timed out. Try again.")), timeoutMs, ); }), ]); } finally { clearTimeout(timer); } } private async call(message: MessageLike) { if (this.closed) throw new Error("Capture shortcut registration closed."); const reply = await this.wait(this.bus.call(new Message(message))); if (!reply) throw new Error("Missing shortcut portal reply."); return reply; } private closeObject(path: string, iface: string) { this.bus.send( new Message({ destination: this.owner, path, interface: iface, member: "Close", flags: MessageFlag.NO_REPLY_EXPECTED, }), ); } private message = (message: Message) => { if (this.closed || message.type !== MessageType.SIGNAL) return; if ( message.sender === "org.freedesktop.DBus" && message.interface === DBUS && message.member === "NameOwnerChanged" && message.body[0] === PORTAL && message.body[1] === this.owner ) { this.failed(new Error("The desktop shortcut service restarted. Retry the shortcut request.")); return; } if (!this.owner || message.sender !== this.owner) return; if ( message.interface === REQUEST && message.member === "Response" && message.path.startsWith(this.namespace) ) { if (message.path === this.pending?.path) this.pending.resolve(message.body); else if (this.responses.size < 8) this.responses.set(message.path, message.body); return; } if ( this.session && message.path === this.session && message.interface === SESSION && message.member === "Closed" ) { this.failed( new Error("Your desktop closed the capture shortcut. Retry the shortcut request."), ); return; } if ( message.path !== PATH || message.interface !== SHORTCUTS || message.body[0] !== this.session ) return; if ( message.member === "Activated" && message.signature === "osta{sv}" && message.body[1] === this.shortcutId && (this.state.shortcutRegistered || this.state.shortcutActionRegistered) ) this.onCapture(); if (message.member === "ShortcutsChanged") { try { this.bound(decodeShortcuts(message.body[1])); } catch (error) { this.failed(error); } } }; private async request( member: string, signature: string, body: unknown[], options: Record<string, Variant<unknown>> = {}, ) { const token = `t3_${NodeCrypto.randomUUID().replaceAll("-", "")}`; const expectedPath = this.namespace + token; let resolve!: (body: unknown) => void; const response = new Promise<unknown>((done) => { resolve = done; }); this.pending = { path: expectedPath, resolve }; this.responses.clear(); let completed = false; try { const reply = await this.call({ destination: this.owner, path: PATH, interface: SHORTCUTS, member, signature: signature + "a{sv}", body: [...body, { ...options, handle_token: new Variant("s", token) }], }); const handle = string(reply.body[0]); if (!handle.startsWith(this.namespace)) throw new Error("Invalid shortcut request handle."); this.pending.path = handle; if (this.responses.has(handle)) resolve(this.responses.get(handle)); const [status, results] = decodeResponse( await this.wait(response, member === "BindShortcuts" ? 120_000 : 5_000), ); completed = true; if (status !== 0) { if (member === "BindShortcuts") { this.update({ shortcutRegistered: false, shortcutPending: false, shortcutMessage: this.version >= 2 ? "Shortcut permission wasn't granted. Open shortcut permissions to allow it." : "Shortcut permission wasn't granted. Allow T3 Code in your desktop's shortcut settings.", }); return undefined; } throw new Error("Your desktop could not create a capture shortcut session."); } return results; } finally { if (!completed && !this.closed && this.pending) this.closeObject(this.pending.path, REQUEST); this.pending = undefined; this.responses.clear(); } } private bound(shortcuts: typeof Shortcuts.Type) { const shortcut = shortcuts.find(([id]) => id === this.shortcutId); if (this.managedByHyprland) { this.update({ shortcutRegistered: false, shortcutActionRegistered: Boolean(shortcut), shortcutPending: false, shortcutMessage: shortcut ? "Managed by Hyprland. Add the binding to your config and save it." : "Hyprland did not register the capture action. Check that xdg-desktop-portal-hyprland is running, then restart T3 Code.", }); return; } const label = shortcut?.[1].trigger_description?.value.trim(); this.update({ shortcutRegistered: Boolean(shortcut && label), shortcutPending: false, ...(label ? { shortcutLabel: label } : {}), shortcutMessage: label ? `Desktop shortcut: ${label}` : this.version >= 2 ? "No shortcut is assigned. Open shortcut permissions to choose one." : "No shortcut is assigned. Choose one in your desktop's shortcut settings.", }); } private async initialize(appId: string, shortcut: SnapShotKeyChord) { const trigger = portalShortcutTrigger(shortcut); if (!process.env.FLATPAK_ID && !process.env.SNAP) { await this.call({ destination: PORTAL, path: PATH, interface: "org.freedesktop.host.portal.Registry", member: "Register", signature: "sa{sv}", body: [appId, {}], }).catch((error: unknown) => { if ( !( error instanceof DBusError && ["UnknownMethod", "UnknownInterface"].some( (name) => error.type === `${DBUS}.Error.${name}`, ) ) ) throw error; }); } const owner = await this.call({ destination: DBUS, path: "/org/freedesktop/DBus", interface: DBUS, member: "GetNameOwner", signature: "s", body: [PORTAL], }); this.owner = string(owner.body[0]); this.namespace = `${PATH}/request/${owner.destination.slice(1).replaceAll(".", "_")}/`; const version = await this.call({ destination: this.owner, path: PATH, interface: "org.freedesktop.DBus.Properties", member: "Get", signature: "ss", body: [SHORTCUTS, "version"], }); this.version = decodeVersion(version.body[0]).value; for (const rule of [ `type='signal',sender='${this.owner}',path_namespace='${PATH}'`, `type='signal',sender='org.freedesktop.DBus',interface='${DBUS}',member='NameOwnerChanged',arg0='${PORTAL}'`, ]) await this.call({ destination: DBUS, path: "/org/freedesktop/DBus", interface: DBUS, member: "AddMatch", signature: "s", body: [rule], }); const created = await this.request("CreateSession", "", [], { session_handle_token: new Variant( "s", `t3_capture_${NodeCrypto.randomUUID().replaceAll("-", "")}`, ), }); const session = decodeSession(created).session_handle.value; const sessionNamespace = this.namespace.replace("/request/", "/session/"); if (!session.startsWith(sessionNamespace)) throw new Error("Invalid shortcut session handle."); this.session = session; this.shortcutId = this.managedByHyprland ? HYPRLAND_CAPTURE_ACTION : `t3-snap-shot-${NodeCrypto.createHash("sha256").update(trigger).digest("hex").slice(0, 16)}`; // Every session must bind, even when the desktop remembers this shortcut's approval. const bound = await this.request("BindShortcuts", "oa(sa{sv})s", [ this.session, [ [ this.shortcutId, { description: new Variant("s", "Capture a window"), ...(!this.managedByHyprland ? { preferred_trigger: new Variant("s", trigger) } : {}), }, ], ], "", ]); if (bound) this.bound(decodeShortcutsResult(bound).shortcuts.value); }}
// @effect-diagnostics nodeBuiltinImport:off -- Stable shortcut IDs and unique portal request tokens.
// @effect-diagnostics globalTimers:off -- Bounded D-Bus calls and user-consent requests at the native boundary.
import * as NodeCrypto from "node:crypto";
import {
DBusError,
Message,
MessageFlag,
MessageType,
Variant,
sessionBus,
type MessageBus,
type MessageLike,
} from "dbus-next";
import * as Schema from "effect/Schema";
import type { SnapShotKeyChord } from "@t3tools/contracts";
import { HYPRLAND_CAPTURE_ACTION, portalShortcutTrigger } from "./linuxCaptureSession.ts";
export { portalShortcutTrigger } from "./linuxCaptureSession.ts";
const PORTAL = "org.freedesktop.portal.Desktop";
const PATH = "/org/freedesktop/portal/desktop";
const SHORTCUTS = "org.freedesktop.portal.GlobalShortcuts";
const REQUEST = "org.freedesktop.portal.Request";
const SESSION = "org.freedesktop.portal.Session";
const DBUS = "org.freedesktop.DBus";
const string = Schema.decodeUnknownSync(Schema.String);
const StringVariant = Schema.Struct({ signature: Schema.Literal("s"), value: Schema.String });
const Shortcuts = Schema.Array(
Schema.Tuple([
Schema.String,
Schema.Struct({
description: Schema.optional(StringVariant),
trigger_description: Schema.optional(StringVariant),
}),
]),
);
const decodeShortcuts = Schema.decodeUnknownSync(Shortcuts);
const decodeShortcutsResult = Schema.decodeUnknownSync(
Schema.Struct({
shortcuts: Schema.Struct({ signature: Schema.Literal("a(sa{sv})"), value: Shortcuts }),
}),
);
const decodeSession = Schema.decodeUnknownSync(Schema.Struct({ session_handle: StringVariant }));
const decodeResponse = Schema.decodeUnknownSync(
Schema.Tuple([Schema.Int, Schema.Record(Schema.String, Schema.Unknown)]),
);
const decodeVersion = Schema.decodeUnknownSync(
Schema.Struct({
signature: Schema.Literal("u"),
value: Schema.Int,
}),
);
export interface PortalShortcutState {
readonly shortcutActionRegistered?: boolean;
readonly shortcutRegistered: boolean;
readonly shortcutPending: boolean;
/** Whether retry-shortcut can reopen permissions or start a new session. */
readonly shortcutCanRetry?: boolean;
readonly shortcutLabel?: string;
readonly shortcutMessage: string | null;
}
/** Own the portal session, including consent and release; Electron only reports submission. */
export class PortalCaptureShortcut {
state: PortalShortcutState = {
shortcutRegistered: false,
shortcutPending: true,
shortcutMessage: "Waiting for shortcut permission. Approve the desktop prompt if one appears.",
};
readonly ready: Promise<void>;
private closed = false;
private owner = "";
private namespace = "";
private session = "";
private shortcutId = "";
private version = 0;
private pending: { path: string; resolve: (body: unknown) => void } | undefined;
private responses = new Map<string, unknown>();
private readonly stopped: Promise<never>;
private rejectStopped!: (reason: Error) => void;
private readonly onCapture: () => void;
private readonly onStateChanged: () => void;
private readonly bus: MessageBus;
private readonly managedByHyprland: boolean;
constructor(
appId: string,
shortcut: SnapShotKeyChord,
onCapture: () => void,
onStateChanged: () => void,
bus: MessageBus = sessionBus(),
managedByHyprland = false,
) {
this.onCapture = onCapture;
this.onStateChanged = onStateChanged;
this.bus = bus;
this.managedByHyprland = managedByHyprland;
if (managedByHyprland)
this.state = {
shortcutRegistered: false,
shortcutPending: true,
shortcutMessage: "Connecting to Hyprland shortcuts…",
};
this.stopped = new Promise((_, reject) => {
this.rejectStopped = reject;
});
void this.stopped.catch(() => undefined);
bus.on("error", this.failed);
bus.on("message", this.message);
this.ready = this.initialize(appId, shortcut).catch(this.failed);
}
close = () => {
if (this.closed) return;
this.closed = true;
this.rejectStopped(new Error("Capture shortcut registration closed."));
try {
if (this.pending) this.closeObject(this.pending.path, REQUEST);
if (this.session) this.closeObject(this.session, SESSION);
} catch {
// A broken bus is already closing its sessions; local cleanup must still run.
}
this.bus.removeListener("message", this.message);
this.responses.clear();
this.bus.disconnect();
};
/** A previously denied binding is changed by the desktop, not by bypassing its decision. */
get hasSession() {
return !this.closed && Boolean(this.session);
}
async configure() {
if (this.managedByHyprland)
throw new Error("Change the capture binding in your Hyprland config, then save it.");
if (!this.hasSession || this.version < 2)
throw new Error(
"Open your desktop's shortcut settings and allow T3 Code's capture shortcut.",
);
await this.call({
destination: this.owner,
path: PATH,
interface: SHORTCUTS,
member: "ConfigureShortcuts",
signature: "osa{sv}",
body: [this.session, "", {}],
});
}
private update(state: PortalShortcutState) {
if (this.closed) return;
this.state = {
shortcutCanRetry: !this.managedByHyprland && (!this.hasSession || this.version >= 2),
...state,
};
this.onStateChanged();
}
private failed = (error: unknown) => {
if (this.closed) return;
this.update({
shortcutRegistered: false,
shortcutPending: false,
// This failed session is closing, so retry can register a fresh one.
shortcutCanRetry: !this.managedByHyprland,
shortcutMessage: this.managedByHyprland
? "Couldn't connect to Hyprland shortcuts. Make sure xdg-desktop-portal-hyprland is running, then restart T3 Code."
: error instanceof Error
? error.message
: "Could not register the capture shortcut.",
});
this.close();
};
private async wait<T>(promise: Promise<T>, timeoutMs = 5_000): Promise<T> {
let timer: ReturnType<typeof setTimeout> | undefined;
try {
return await Promise.race([
promise,
this.stopped,
new Promise<never>((_, reject) => {
timer = setTimeout(
() => reject(new Error("Shortcut permission request timed out. Try again.")),
timeoutMs,
);
}),
]);
} finally {
clearTimeout(timer);
}
}
private async call(message: MessageLike) {
if (this.closed) throw new Error("Capture shortcut registration closed.");
const reply = await this.wait(this.bus.call(new Message(message)));
if (!reply) throw new Error("Missing shortcut portal reply.");
return reply;
}
private closeObject(path: string, iface: string) {
this.bus.send(
new Message({
destination: this.owner,
path,
interface: iface,
member: "Close",
flags: MessageFlag.NO_REPLY_EXPECTED,
}),
);
}
private message = (message: Message) => {
if (this.closed || message.type !== MessageType.SIGNAL) return;
if (
message.sender === "org.freedesktop.DBus" &&
message.interface === DBUS &&
message.member === "NameOwnerChanged" &&
message.body[0] === PORTAL &&
message.body[1] === this.owner
) {
this.failed(new Error("The desktop shortcut service restarted. Retry the shortcut request."));
return;
}
if (!this.owner || message.sender !== this.owner) return;
if (
message.interface === REQUEST &&
message.member === "Response" &&
message.path.startsWith(this.namespace)
) {
if (message.path === this.pending?.path) this.pending.resolve(message.body);
else if (this.responses.size < 8) this.responses.set(message.path, message.body);
return;
}
if (
this.session &&
message.path === this.session &&
message.interface === SESSION &&
message.member === "Closed"
) {
this.failed(
new Error("Your desktop closed the capture shortcut. Retry the shortcut request."),
);
return;
}
if (
message.path !== PATH ||
message.interface !== SHORTCUTS ||
message.body[0] !== this.session
)
return;
if (
message.member === "Activated" &&
message.signature === "osta{sv}" &&
message.body[1] === this.shortcutId &&
(this.state.shortcutRegistered || this.state.shortcutActionRegistered)
)
this.onCapture();
if (message.member === "ShortcutsChanged") {
try {
this.bound(decodeShortcuts(message.body[1]));
} catch (error) {
this.failed(error);
}
}
};
private async request(
member: string,
signature: string,
body: unknown[],
options: Record<string, Variant<unknown>> = {},
) {
const token = `t3_${NodeCrypto.randomUUID().replaceAll("-", "")}`;
const expectedPath = this.namespace + token;
let resolve!: (body: unknown) => void;
const response = new Promise<unknown>((done) => {
resolve = done;
});
this.pending = { path: expectedPath, resolve };
this.responses.clear();
let completed = false;
try {
const reply = await this.call({
destination: this.owner,
path: PATH,
interface: SHORTCUTS,
member,
signature: signature + "a{sv}",
body: [...body, { ...options, handle_token: new Variant("s", token) }],
});
const handle = string(reply.body[0]);
if (!handle.startsWith(this.namespace)) throw new Error("Invalid shortcut request handle.");
this.pending.path = handle;
if (this.responses.has(handle)) resolve(this.responses.get(handle));
const [status, results] = decodeResponse(
await this.wait(response, member === "BindShortcuts" ? 120_000 : 5_000),
);
completed = true;
if (status !== 0) {
if (member === "BindShortcuts") {
this.update({
shortcutRegistered: false,
shortcutPending: false,
shortcutMessage:
this.version >= 2
? "Shortcut permission wasn't granted. Open shortcut permissions to allow it."
: "Shortcut permission wasn't granted. Allow T3 Code in your desktop's shortcut settings.",
});
return undefined;
}
throw new Error("Your desktop could not create a capture shortcut session.");
}
return results;
} finally {
if (!completed && !this.closed && this.pending) this.closeObject(this.pending.path, REQUEST);
this.pending = undefined;
this.responses.clear();
}
}
private bound(shortcuts: typeof Shortcuts.Type) {
const shortcut = shortcuts.find(([id]) => id === this.shortcutId);
if (this.managedByHyprland) {
this.update({
shortcutRegistered: false,
shortcutActionRegistered: Boolean(shortcut),
shortcutPending: false,
shortcutMessage: shortcut
? "Managed by Hyprland. Add the binding to your config and save it."
: "Hyprland did not register the capture action. Check that xdg-desktop-portal-hyprland is running, then restart T3 Code.",
});
return;
}
const label = shortcut?.[1].trigger_description?.value.trim();
this.update({
shortcutRegistered: Boolean(shortcut && label),
shortcutPending: false,
...(label ? { shortcutLabel: label } : {}),
shortcutMessage: label
? `Desktop shortcut: ${label}`
: this.version >= 2
? "No shortcut is assigned. Open shortcut permissions to choose one."
: "No shortcut is assigned. Choose one in your desktop's shortcut settings.",
});
}
private async initialize(appId: string, shortcut: SnapShotKeyChord) {
const trigger = portalShortcutTrigger(shortcut);
if (!process.env.FLATPAK_ID && !process.env.SNAP) {
await this.call({
destination: PORTAL,
path: PATH,
interface: "org.freedesktop.host.portal.Registry",
member: "Register",
signature: "sa{sv}",
body: [appId, {}],
}).catch((error: unknown) => {
if (
!(
error instanceof DBusError &&
["UnknownMethod", "UnknownInterface"].some(
(name) => error.type === `${DBUS}.Error.${name}`,
)
)
)
throw error;
});
}
const owner = await this.call({
destination: DBUS,
path: "/org/freedesktop/DBus",
interface: DBUS,
member: "GetNameOwner",
signature: "s",
body: [PORTAL],
});
this.owner = string(owner.body[0]);
this.namespace = `${PATH}/request/${owner.destination.slice(1).replaceAll(".", "_")}/`;
const version = await this.call({
destination: this.owner,
path: PATH,
interface: "org.freedesktop.DBus.Properties",
member: "Get",
signature: "ss",
body: [SHORTCUTS, "version"],
});
this.version = decodeVersion(version.body[0]).value;
for (const rule of [
`type='signal',sender='${this.owner}',path_namespace='${PATH}'`,
`type='signal',sender='org.freedesktop.DBus',interface='${DBUS}',member='NameOwnerChanged',arg0='${PORTAL}'`,
])
await this.call({
destination: DBUS,
path: "/org/freedesktop/DBus",
interface: DBUS,
member: "AddMatch",
signature: "s",
body: [rule],
});
const created = await this.request("CreateSession", "", [], {
session_handle_token: new Variant(
"s",
`t3_capture_${NodeCrypto.randomUUID().replaceAll("-", "")}`,
),
});
const session = decodeSession(created).session_handle.value;
const sessionNamespace = this.namespace.replace("/request/", "/session/");
if (!session.startsWith(sessionNamespace)) throw new Error("Invalid shortcut session handle.");
this.session = session;
this.shortcutId = this.managedByHyprland
? HYPRLAND_CAPTURE_ACTION
: `t3-snap-shot-${NodeCrypto.createHash("sha256").update(trigger).digest("hex").slice(0, 16)}`;
// Every session must bind, even when the desktop remembers this shortcut's approval.
const bound = await this.request("BindShortcuts", "oa(sa{sv})s", [
this.session,
[
[
this.shortcutId,
{
description: new Variant("s", "Capture a window"),
...(!this.managedByHyprland ? { preferred_trigger: new Variant("s", trigger) } : {}),
},
],
],
"",
]);
if (bound) this.bound(decodeShortcutsResult(bound).shortcuts.value);
}
}