feat: press in-game keys based on keyboard events

This commit is contained in:
2026-05-31 22:17:19 +02:00
parent 98f0fd10b0
commit 3968e775cc
4 changed files with 49 additions and 14 deletions

View File

@@ -17,5 +17,8 @@
"run_at": "document_idle"
}
],
"permissions": ["storage"]
"background": {
"service_worker": "dist/background.js"
},
"permissions": ["storage", "tabs", "debugger"]
}

View File

@@ -3,8 +3,8 @@
"version": "1.0.0",
"description": "Tweaks for WoV Assassins Convention",
"scripts": {
"build": "esbuild src/content.ts src/popup.ts --bundle --outdir=dist --platform=browser --target=chrome120",
"watch": "esbuild src/content.ts src/popup.ts --bundle --outdir=dist --platform=browser --target=chrome120 --watch",
"build": "esbuild src/content.ts src/popup.ts src/background.ts --bundle --outdir=dist --platform=browser --target=chrome120",
"watch": "esbuild src/content.ts src/popup.ts src/background.ts --bundle --outdir=dist --platform=browser --target=chrome120 --watch",
"dev": "pnpm watch"
},
"devDependencies": {

28
src/background.ts Normal file
View File

@@ -0,0 +1,28 @@
type SimulateClickMessage = {
type: "simulate-click";
x: number;
y: number;
};
chrome.runtime.onMessage.addListener((message: SimulateClickMessage) => {
if (message.type !== "simulate-click") return;
const { x, y } = message;
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (!tabs[0]?.id) return;
const target = { tabId: tabs[0].id! };
chrome.debugger.attach(target, "1.2", () => {
if (chrome.runtime.lastError) return;
chrome.debugger.sendCommand(target, "Input.dispatchMouseEvent", { type: "mouseMoved", x, y }, () => {
chrome.debugger.sendCommand(target, "Input.dispatchMouseEvent", { type: "mousePressed", button: "left", x, y, clickCount: 1 }, () => {
chrome.debugger.sendCommand(target, "Input.dispatchMouseEvent", { type: "mouseReleased", button: "left", x, y, clickCount: 1 }, () => {
chrome.debugger.detach(target);
});
});
});
});
});
});

View File

@@ -1,14 +1,13 @@
import { State, STORAGE_KEY } from "./types";
const KEY_BINDINGS: Record<string, string> = {
// TODO
};
let enabled = false;
const clickButton = (selector: string): void => {
const el = document.querySelector<HTMLElement>(selector);
el?.click();
const findButtonForKey = (key: string): HTMLElement | null => {
if (key.length !== 1 || !/[a-zA-Z]/.test(key)) return null;
const letter = key.toUpperCase();
const label = Array.from(document.querySelectorAll<HTMLElement>("div[dir=\"auto\"]"))
.find(el => el.textContent === letter);
return label?.closest<HTMLElement>("[tabindex=\"0\"]") ?? null;
};
const onKeyDown = (event: KeyboardEvent): void => {
@@ -21,10 +20,15 @@ const onKeyDown = (event: KeyboardEvent): void => {
target.isContentEditable
) return;
const selector = KEY_BINDINGS[event.code];
if (selector) {
const btn = findButtonForKey(event.key);
if (btn) {
event.preventDefault();
clickButton(selector);
const rect = btn.getBoundingClientRect();
chrome.runtime.sendMessage({
type: "simulate-click",
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
});
}
};
@@ -33,7 +37,7 @@ const init = async (): Promise<void> => {
const state = result[STORAGE_KEY] as State | undefined;
enabled = state?.enabled ?? true;
document.addEventListener("keydown", onKeyDown);
document.addEventListener("keydown", onKeyDown, { capture: true });
chrome.storage.onChanged.addListener((changes) => {
if (STORAGE_KEY in changes) {