Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: Victor Navarro <vn4varro@gmail.com> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: Dax Raad <d@ironbay.co> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: Nabs <nabil@instafork.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com> Co-authored-by: AidenGeunGeun <eastlandwyvern@gmail.com> Co-authored-by: Mark <geraint0923@users.noreply.github.com> Co-authored-by: Aiden Cline <aidenpcline@gmail.com> Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com> Co-authored-by: Jay <air@live.ca> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: BB84 <110078428+BB-84C@users.noreply.github.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Sebastian <hasta84@gmail.com> Co-authored-by: Jérôme Benoit <jerome.benoit@sap.com> Co-authored-by: Test User <test@test.com> Co-authored-by: Simon Klee <hello@simonklee.dk> Co-authored-by: Rahul A Mistry <149420892+ProdigyRahul@users.noreply.github.com> Co-authored-by: Qiping Li <liqiping1991@gmail.com> Co-authored-by: liqiping <liqiping@msh.team> Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com> Co-authored-by: Matthias Reso <13337103+mreso@users.noreply.github.com> Co-authored-by: tobwen <1864057+tobwen@users.noreply.github.com>
95 lines
2.6 KiB
TypeScript
95 lines
2.6 KiB
TypeScript
import type { WebContents } from "electron"
|
|
|
|
const focusDebuggerOwners = new WeakSet<WebContents>()
|
|
const forcedFocusNodes = new WeakMap<WebContents, number[]>()
|
|
const focusableSelector = `
|
|
a[href],
|
|
button:not([disabled]),
|
|
input:not([disabled]),
|
|
select:not([disabled]),
|
|
textarea:not([disabled]),
|
|
summary,
|
|
[contenteditable="true"],
|
|
[tabindex]:not([tabindex="-1"])
|
|
`
|
|
|
|
export async function setForceFocus(contents: WebContents, enabled: boolean) {
|
|
const debuggerApi = contents.debugger
|
|
if (!debuggerApi.isAttached()) {
|
|
if (!enabled) {
|
|
focusDebuggerOwners.delete(contents)
|
|
forcedFocusNodes.delete(contents)
|
|
return
|
|
}
|
|
debuggerApi.attach("1.3")
|
|
focusDebuggerOwners.add(contents)
|
|
debuggerApi.once("detach", () => {
|
|
focusDebuggerOwners.delete(contents)
|
|
forcedFocusNodes.delete(contents)
|
|
})
|
|
}
|
|
|
|
if (!enabled) {
|
|
await Promise.allSettled(
|
|
(forcedFocusNodes.get(contents) ?? []).map((nodeId) =>
|
|
debuggerApi.sendCommand("CSS.forcePseudoState", {
|
|
nodeId,
|
|
forcedPseudoClasses: [],
|
|
}),
|
|
),
|
|
)
|
|
forcedFocusNodes.delete(contents)
|
|
if (!focusDebuggerOwners.delete(contents)) return
|
|
debuggerApi.detach()
|
|
return
|
|
}
|
|
|
|
await debuggerApi.sendCommand("DOM.enable")
|
|
await debuggerApi.sendCommand("CSS.enable")
|
|
const document: unknown = await debuggerApi.sendCommand("DOM.getDocument", {
|
|
depth: -1,
|
|
pierce: true,
|
|
})
|
|
const nodes: unknown = await debuggerApi.sendCommand("DOM.querySelectorAll", {
|
|
nodeId: readDocumentNodeId(document),
|
|
selector: focusableSelector,
|
|
})
|
|
const nodeIds = readNodeIds(nodes)
|
|
forcedFocusNodes.set(contents, [...new Set([...(forcedFocusNodes.get(contents) ?? []), ...nodeIds])])
|
|
await Promise.allSettled(
|
|
nodeIds.map((nodeId) =>
|
|
debuggerApi.sendCommand("CSS.forcePseudoState", {
|
|
nodeId,
|
|
forcedPseudoClasses: ["focus", "focus-visible"],
|
|
}),
|
|
),
|
|
)
|
|
}
|
|
|
|
function readDocumentNodeId(value: unknown) {
|
|
if (
|
|
!value ||
|
|
typeof value !== "object" ||
|
|
!("root" in value) ||
|
|
!value.root ||
|
|
typeof value.root !== "object" ||
|
|
!("nodeId" in value.root) ||
|
|
typeof value.root.nodeId !== "number"
|
|
) {
|
|
throw new Error("Invalid DOM.getDocument response")
|
|
}
|
|
return value.root.nodeId
|
|
}
|
|
|
|
function readNodeIds(value: unknown) {
|
|
if (
|
|
!value ||
|
|
typeof value !== "object" ||
|
|
!("nodeIds" in value) ||
|
|
!Array.isArray(value.nodeIds) ||
|
|
!value.nodeIds.every((nodeId) => typeof nodeId === "number")
|
|
) {
|
|
throw new Error("Invalid DOM.querySelectorAll response")
|
|
}
|
|
return value.nodeIds
|
|
}
|