mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 03:34:03 +00:00
ed3c7b1a22
## Description: This PR makes several existing keybinds configurable that were previously fixed and could not be changed in the keybind settings. This is one of the required PRs to fully remove all keybind explanations from the HelpModal. This work is based on the following feedback by @ryanbarlow97: > "This probably needs to be redone / removed from help, and just have a section saying how to get to the keybinds modal inside settings" > https://github.com/openfrontio/OpenFrontIO/pull/2872#issuecomment-3740006017 Some keybinds described in the HelpModal already existed internally, but users had no way to change them. By making these keybinds configurable, we can now safely replace those explanations with a simple reference to the keybind settings instead. This helps: - Remove keybind explanations from the HelpModal ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: aotumuri Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
699 lines
19 KiB
TypeScript
699 lines
19 KiB
TypeScript
import { EventBus, GameEvent } from "../core/EventBus";
|
|
import { UnitType } from "../core/game/Game";
|
|
import { UnitView } from "../core/game/GameView";
|
|
import { UserSettings } from "../core/game/UserSettings";
|
|
import { UIState } from "./graphics/UIState";
|
|
import { ReplaySpeedMultiplier } from "./utilities/ReplaySpeedMultiplier";
|
|
|
|
export class MouseUpEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
export class MouseOverEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
export class TouchEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
/**
|
|
* Event emitted when a unit is selected or deselected
|
|
*/
|
|
export class UnitSelectionEvent implements GameEvent {
|
|
constructor(
|
|
public readonly unit: UnitView | null,
|
|
public readonly isSelected: boolean,
|
|
) {}
|
|
}
|
|
|
|
export class MouseDownEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
export class MouseMoveEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
export class ContextMenuEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
export class ZoomEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
public readonly delta: number,
|
|
) {}
|
|
}
|
|
|
|
export class DragEvent implements GameEvent {
|
|
constructor(
|
|
public readonly deltaX: number,
|
|
public readonly deltaY: number,
|
|
) {}
|
|
}
|
|
|
|
export class AlternateViewEvent implements GameEvent {
|
|
constructor(public readonly alternateView: boolean) {}
|
|
}
|
|
|
|
export class CloseViewEvent implements GameEvent {}
|
|
|
|
export class RefreshGraphicsEvent implements GameEvent {}
|
|
|
|
export class TogglePerformanceOverlayEvent implements GameEvent {}
|
|
|
|
export class ToggleStructureEvent implements GameEvent {
|
|
constructor(public readonly structureTypes: UnitType[] | null) {}
|
|
}
|
|
|
|
export class GhostStructureChangedEvent implements GameEvent {
|
|
constructor(public readonly ghostStructure: UnitType | null) {}
|
|
}
|
|
|
|
export class SwapRocketDirectionEvent implements GameEvent {
|
|
constructor(public readonly rocketDirectionUp: boolean) {}
|
|
}
|
|
|
|
export class ShowBuildMenuEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
export class ShowEmojiMenuEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
export class DoBoatAttackEvent implements GameEvent {}
|
|
|
|
export class DoGroundAttackEvent implements GameEvent {}
|
|
|
|
export class AttackRatioEvent implements GameEvent {
|
|
constructor(public readonly attackRatio: number) {}
|
|
}
|
|
|
|
export class ReplaySpeedChangeEvent implements GameEvent {
|
|
constructor(public readonly replaySpeedMultiplier: ReplaySpeedMultiplier) {}
|
|
}
|
|
|
|
export class CenterCameraEvent implements GameEvent {
|
|
constructor() {}
|
|
}
|
|
|
|
export class AutoUpgradeEvent implements GameEvent {
|
|
constructor(
|
|
public readonly x: number,
|
|
public readonly y: number,
|
|
) {}
|
|
}
|
|
|
|
export class TickMetricsEvent implements GameEvent {
|
|
constructor(
|
|
public readonly tickExecutionDuration?: number,
|
|
public readonly tickDelay?: number,
|
|
) {}
|
|
}
|
|
|
|
export class InputHandler {
|
|
private lastPointerX: number = 0;
|
|
private lastPointerY: number = 0;
|
|
|
|
private lastPointerDownX: number = 0;
|
|
private lastPointerDownY: number = 0;
|
|
|
|
private pointers: Map<number, PointerEvent> = new Map();
|
|
|
|
private lastPinchDistance: number = 0;
|
|
|
|
private pointerDown: boolean = false;
|
|
|
|
private alternateView = false;
|
|
|
|
private moveInterval: NodeJS.Timeout | null = null;
|
|
private activeKeys = new Set<string>();
|
|
private keybinds: Record<string, string> = {};
|
|
|
|
private readonly PAN_SPEED = 5;
|
|
private readonly ZOOM_SPEED = 10;
|
|
|
|
private readonly userSettings: UserSettings = new UserSettings();
|
|
|
|
constructor(
|
|
public uiState: UIState,
|
|
private canvas: HTMLCanvasElement,
|
|
private eventBus: EventBus,
|
|
) {}
|
|
|
|
initialize() {
|
|
let saved: Record<string, string> = {};
|
|
try {
|
|
const parsed = JSON.parse(
|
|
localStorage.getItem("settings.keybinds") ?? "{}",
|
|
);
|
|
// flatten { key: {key, value} } → { key: value } and accept legacy string values
|
|
saved = Object.fromEntries(
|
|
Object.entries(parsed)
|
|
.map(([k, v]) => {
|
|
// Extract value from nested object or plain string
|
|
let val: unknown;
|
|
if (v && typeof v === "object" && "value" in v) {
|
|
val = (v as { value: unknown }).value;
|
|
} else {
|
|
val = v;
|
|
}
|
|
|
|
// Map invalid values to undefined (filtered later)
|
|
if (typeof val !== "string") {
|
|
return [k, undefined];
|
|
}
|
|
return [k, val];
|
|
})
|
|
.filter(([, v]) => typeof v === "string"),
|
|
) as Record<string, string>;
|
|
} catch (e) {
|
|
console.warn("Invalid keybinds JSON:", e);
|
|
}
|
|
|
|
// Mac users might have different keybinds
|
|
const isMac = /Mac/.test(navigator.userAgent);
|
|
|
|
this.keybinds = {
|
|
toggleView: "Space",
|
|
centerCamera: "KeyC",
|
|
moveUp: "KeyW",
|
|
moveDown: "KeyS",
|
|
moveLeft: "KeyA",
|
|
moveRight: "KeyD",
|
|
zoomOut: "KeyQ",
|
|
zoomIn: "KeyE",
|
|
attackRatioDown: "KeyT",
|
|
attackRatioUp: "KeyY",
|
|
boatAttack: "KeyB",
|
|
groundAttack: "KeyG",
|
|
swapDirection: "KeyU",
|
|
modifierKey: isMac ? "MetaLeft" : "ControlLeft",
|
|
altKey: "AltLeft",
|
|
buildCity: "Digit1",
|
|
buildFactory: "Digit2",
|
|
buildPort: "Digit3",
|
|
buildDefensePost: "Digit4",
|
|
buildMissileSilo: "Digit5",
|
|
buildSamLauncher: "Digit6",
|
|
buildWarship: "Digit7",
|
|
buildAtomBomb: "Digit8",
|
|
buildHydrogenBomb: "Digit9",
|
|
buildMIRV: "Digit0",
|
|
...saved,
|
|
};
|
|
|
|
this.canvas.addEventListener("pointerdown", (e) => this.onPointerDown(e));
|
|
window.addEventListener("pointerup", (e) => this.onPointerUp(e));
|
|
this.canvas.addEventListener(
|
|
"wheel",
|
|
(e) => {
|
|
this.onScroll(e);
|
|
this.onShiftScroll(e);
|
|
e.preventDefault();
|
|
},
|
|
{ passive: false },
|
|
);
|
|
window.addEventListener("pointermove", this.onPointerMove.bind(this));
|
|
this.canvas.addEventListener("contextmenu", (e) => this.onContextMenu(e));
|
|
window.addEventListener("mousemove", (e) => {
|
|
if (e.movementX || e.movementY) {
|
|
this.eventBus.emit(new MouseMoveEvent(e.clientX, e.clientY));
|
|
}
|
|
});
|
|
this.pointers.clear();
|
|
|
|
this.moveInterval = setInterval(() => {
|
|
let deltaX = 0;
|
|
let deltaY = 0;
|
|
|
|
// Skip if shift is held down
|
|
if (
|
|
this.activeKeys.has("ShiftLeft") ||
|
|
this.activeKeys.has("ShiftRight")
|
|
) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
this.activeKeys.has(this.keybinds.moveUp) ||
|
|
this.activeKeys.has("ArrowUp")
|
|
)
|
|
deltaY += this.PAN_SPEED;
|
|
if (
|
|
this.activeKeys.has(this.keybinds.moveDown) ||
|
|
this.activeKeys.has("ArrowDown")
|
|
)
|
|
deltaY -= this.PAN_SPEED;
|
|
if (
|
|
this.activeKeys.has(this.keybinds.moveLeft) ||
|
|
this.activeKeys.has("ArrowLeft")
|
|
)
|
|
deltaX += this.PAN_SPEED;
|
|
if (
|
|
this.activeKeys.has(this.keybinds.moveRight) ||
|
|
this.activeKeys.has("ArrowRight")
|
|
)
|
|
deltaX -= this.PAN_SPEED;
|
|
|
|
if (deltaX || deltaY) {
|
|
this.eventBus.emit(new DragEvent(deltaX, deltaY));
|
|
}
|
|
|
|
const cx = window.innerWidth / 2;
|
|
const cy = window.innerHeight / 2;
|
|
|
|
if (
|
|
this.activeKeys.has(this.keybinds.zoomOut) ||
|
|
this.activeKeys.has("Minus")
|
|
) {
|
|
this.eventBus.emit(new ZoomEvent(cx, cy, this.ZOOM_SPEED));
|
|
}
|
|
if (
|
|
this.activeKeys.has(this.keybinds.zoomIn) ||
|
|
this.activeKeys.has("Equal")
|
|
) {
|
|
this.eventBus.emit(new ZoomEvent(cx, cy, -this.ZOOM_SPEED));
|
|
}
|
|
}, 1);
|
|
|
|
window.addEventListener("keydown", (e) => {
|
|
const isTextInput = this.isTextInputTarget(e.target);
|
|
if (isTextInput && e.code !== "Escape") {
|
|
return;
|
|
}
|
|
|
|
if (e.code === this.keybinds.toggleView) {
|
|
e.preventDefault();
|
|
if (!this.alternateView) {
|
|
this.alternateView = true;
|
|
this.eventBus.emit(new AlternateViewEvent(true));
|
|
}
|
|
}
|
|
|
|
if (e.code === "Escape") {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new CloseViewEvent());
|
|
this.setGhostStructure(null);
|
|
}
|
|
|
|
if (
|
|
[
|
|
this.keybinds.moveUp,
|
|
this.keybinds.moveDown,
|
|
this.keybinds.moveLeft,
|
|
this.keybinds.moveRight,
|
|
this.keybinds.zoomOut,
|
|
this.keybinds.zoomIn,
|
|
"ArrowUp",
|
|
"ArrowLeft",
|
|
"ArrowDown",
|
|
"ArrowRight",
|
|
"Minus",
|
|
"Equal",
|
|
this.keybinds.attackRatioDown,
|
|
this.keybinds.attackRatioUp,
|
|
this.keybinds.centerCamera,
|
|
"ControlLeft",
|
|
"ControlRight",
|
|
"ShiftLeft",
|
|
"ShiftRight",
|
|
].includes(e.code)
|
|
) {
|
|
this.activeKeys.add(e.code);
|
|
}
|
|
});
|
|
window.addEventListener("keyup", (e) => {
|
|
const isTextInput = this.isTextInputTarget(e.target);
|
|
if (isTextInput && !this.activeKeys.has(e.code)) {
|
|
return;
|
|
}
|
|
|
|
if (e.code === this.keybinds.toggleView) {
|
|
e.preventDefault();
|
|
this.alternateView = false;
|
|
this.eventBus.emit(new AlternateViewEvent(false));
|
|
}
|
|
|
|
const resetKey = this.keybinds.resetGfx ?? "KeyR";
|
|
if (e.code === resetKey && this.isAltKeyHeld(e)) {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new RefreshGraphicsEvent());
|
|
}
|
|
|
|
if (e.code === this.keybinds.boatAttack) {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new DoBoatAttackEvent());
|
|
}
|
|
|
|
if (e.code === this.keybinds.groundAttack) {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new DoGroundAttackEvent());
|
|
}
|
|
|
|
if (e.code === this.keybinds.attackRatioDown) {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new AttackRatioEvent(-10));
|
|
}
|
|
|
|
if (e.code === this.keybinds.attackRatioUp) {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new AttackRatioEvent(10));
|
|
}
|
|
|
|
if (e.code === this.keybinds.centerCamera) {
|
|
e.preventDefault();
|
|
this.eventBus.emit(new CenterCameraEvent());
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildCity) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.City);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildFactory) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.Factory);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildPort) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.Port);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildDefensePost) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.DefensePost);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildMissileSilo) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.MissileSilo);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildSamLauncher) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.SAMLauncher);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildAtomBomb) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.AtomBomb);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildHydrogenBomb) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.HydrogenBomb);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildWarship) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.Warship);
|
|
}
|
|
|
|
if (e.code === this.keybinds.buildMIRV) {
|
|
e.preventDefault();
|
|
this.setGhostStructure(UnitType.MIRV);
|
|
}
|
|
|
|
if (e.code === this.keybinds.swapDirection) {
|
|
e.preventDefault();
|
|
const nextDirection = !this.uiState.rocketDirectionUp;
|
|
this.eventBus.emit(new SwapRocketDirectionEvent(nextDirection));
|
|
}
|
|
|
|
// Shift-D to toggle performance overlay
|
|
console.log(e.code, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey);
|
|
if (e.code === "KeyD" && e.shiftKey) {
|
|
e.preventDefault();
|
|
console.log("TogglePerformanceOverlayEvent");
|
|
this.eventBus.emit(new TogglePerformanceOverlayEvent());
|
|
}
|
|
|
|
this.activeKeys.delete(e.code);
|
|
});
|
|
}
|
|
|
|
private onPointerDown(event: PointerEvent) {
|
|
if (event.button === 1) {
|
|
event.preventDefault();
|
|
this.eventBus.emit(new AutoUpgradeEvent(event.clientX, event.clientY));
|
|
return;
|
|
}
|
|
|
|
if (event.button > 0) {
|
|
return;
|
|
}
|
|
|
|
this.pointerDown = true;
|
|
this.pointers.set(event.pointerId, event);
|
|
|
|
if (this.pointers.size === 1) {
|
|
this.lastPointerX = event.clientX;
|
|
this.lastPointerY = event.clientY;
|
|
|
|
this.lastPointerDownX = event.clientX;
|
|
this.lastPointerDownY = event.clientY;
|
|
|
|
this.eventBus.emit(new MouseDownEvent(event.clientX, event.clientY));
|
|
} else if (this.pointers.size === 2) {
|
|
this.lastPinchDistance = this.getPinchDistance();
|
|
}
|
|
}
|
|
|
|
onPointerUp(event: PointerEvent) {
|
|
if (event.button === 1) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
|
|
if (event.button > 0) {
|
|
return;
|
|
}
|
|
this.pointerDown = false;
|
|
this.pointers.clear();
|
|
|
|
if (this.isModifierKeyPressed(event)) {
|
|
this.eventBus.emit(new ShowBuildMenuEvent(event.clientX, event.clientY));
|
|
return;
|
|
}
|
|
if (this.isAltKeyPressed(event)) {
|
|
this.eventBus.emit(new ShowEmojiMenuEvent(event.clientX, event.clientY));
|
|
return;
|
|
}
|
|
|
|
const dist =
|
|
Math.abs(event.x - this.lastPointerDownX) +
|
|
Math.abs(event.y - this.lastPointerDownY);
|
|
if (dist < 10) {
|
|
if (event.pointerType === "touch") {
|
|
this.eventBus.emit(new TouchEvent(event.x, event.y));
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
|
|
if (!this.userSettings.leftClickOpensMenu() || event.shiftKey) {
|
|
this.eventBus.emit(new MouseUpEvent(event.x, event.y));
|
|
} else {
|
|
this.eventBus.emit(new ContextMenuEvent(event.clientX, event.clientY));
|
|
}
|
|
}
|
|
}
|
|
|
|
private onScroll(event: WheelEvent) {
|
|
if (!event.shiftKey) {
|
|
const realCtrl =
|
|
this.activeKeys.has("ControlLeft") ||
|
|
this.activeKeys.has("ControlRight");
|
|
const ratio = event.ctrlKey && !realCtrl ? 10 : 1; // Compensate pinch-zoom low sensitivity
|
|
this.eventBus.emit(new ZoomEvent(event.x, event.y, event.deltaY * ratio));
|
|
}
|
|
}
|
|
|
|
private onShiftScroll(event: WheelEvent) {
|
|
if (event.shiftKey) {
|
|
const scrollValue = event.deltaY === 0 ? event.deltaX : event.deltaY;
|
|
const ratio = scrollValue > 0 ? -10 : 10;
|
|
this.eventBus.emit(new AttackRatioEvent(ratio));
|
|
}
|
|
}
|
|
|
|
private onPointerMove(event: PointerEvent) {
|
|
if (event.button === 1) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
|
|
if (event.button > 0) {
|
|
return;
|
|
}
|
|
|
|
this.pointers.set(event.pointerId, event);
|
|
|
|
if (!this.pointerDown) {
|
|
this.eventBus.emit(new MouseOverEvent(event.clientX, event.clientY));
|
|
return;
|
|
}
|
|
|
|
if (this.pointers.size === 1) {
|
|
const deltaX = event.clientX - this.lastPointerX;
|
|
const deltaY = event.clientY - this.lastPointerY;
|
|
|
|
this.eventBus.emit(new DragEvent(deltaX, deltaY));
|
|
|
|
this.lastPointerX = event.clientX;
|
|
this.lastPointerY = event.clientY;
|
|
} else if (this.pointers.size === 2) {
|
|
const currentPinchDistance = this.getPinchDistance();
|
|
const pinchDelta = currentPinchDistance - this.lastPinchDistance;
|
|
|
|
if (Math.abs(pinchDelta) > 1) {
|
|
const zoomCenter = this.getPinchCenter();
|
|
this.eventBus.emit(
|
|
new ZoomEvent(zoomCenter.x, zoomCenter.y, -pinchDelta * 2),
|
|
);
|
|
this.lastPinchDistance = currentPinchDistance;
|
|
}
|
|
}
|
|
}
|
|
|
|
private onContextMenu(event: MouseEvent) {
|
|
event.preventDefault();
|
|
if (this.uiState.ghostStructure !== null) {
|
|
this.setGhostStructure(null);
|
|
return;
|
|
}
|
|
this.eventBus.emit(new ContextMenuEvent(event.clientX, event.clientY));
|
|
}
|
|
|
|
private setGhostStructure(ghostStructure: UnitType | null) {
|
|
this.uiState.ghostStructure = ghostStructure;
|
|
this.eventBus.emit(new GhostStructureChangedEvent(ghostStructure));
|
|
}
|
|
|
|
private getPinchDistance(): number {
|
|
const pointerEvents = Array.from(this.pointers.values());
|
|
const dx = pointerEvents[0].clientX - pointerEvents[1].clientX;
|
|
const dy = pointerEvents[0].clientY - pointerEvents[1].clientY;
|
|
return Math.sqrt(dx * dx + dy * dy);
|
|
}
|
|
|
|
private getPinchCenter(): { x: number; y: number } {
|
|
const pointerEvents = Array.from(this.pointers.values());
|
|
return {
|
|
x: (pointerEvents[0].clientX + pointerEvents[1].clientX) / 2,
|
|
y: (pointerEvents[0].clientY + pointerEvents[1].clientY) / 2,
|
|
};
|
|
}
|
|
|
|
private isTextInputTarget(target: EventTarget | null): boolean {
|
|
const element = target as HTMLElement | null;
|
|
if (!element) return false;
|
|
if (element.tagName === "TEXTAREA" || element.isContentEditable) {
|
|
return true;
|
|
}
|
|
if (element.tagName === "INPUT") {
|
|
const input = element as HTMLInputElement;
|
|
if (input.id === "attack-ratio" && input.type === "range") {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
destroy() {
|
|
if (this.moveInterval !== null) {
|
|
clearInterval(this.moveInterval);
|
|
}
|
|
this.activeKeys.clear();
|
|
}
|
|
|
|
isModifierKeyPressed(event: PointerEvent): boolean {
|
|
return (
|
|
((this.keybinds.modifierKey === "AltLeft" ||
|
|
this.keybinds.modifierKey === "AltRight") &&
|
|
event.altKey) ||
|
|
((this.keybinds.modifierKey === "ControlLeft" ||
|
|
this.keybinds.modifierKey === "ControlRight") &&
|
|
event.ctrlKey) ||
|
|
((this.keybinds.modifierKey === "ShiftLeft" ||
|
|
this.keybinds.modifierKey === "ShiftRight") &&
|
|
event.shiftKey) ||
|
|
((this.keybinds.modifierKey === "MetaLeft" ||
|
|
this.keybinds.modifierKey === "MetaRight") &&
|
|
event.metaKey)
|
|
);
|
|
}
|
|
|
|
private isAltKeyHeld(event: KeyboardEvent): boolean {
|
|
if (
|
|
this.keybinds.altKey === "AltLeft" ||
|
|
this.keybinds.altKey === "AltRight"
|
|
) {
|
|
return event.altKey && !event.ctrlKey;
|
|
}
|
|
if (
|
|
this.keybinds.altKey === "ControlLeft" ||
|
|
this.keybinds.altKey === "ControlRight"
|
|
) {
|
|
return event.ctrlKey;
|
|
}
|
|
if (
|
|
this.keybinds.altKey === "ShiftLeft" ||
|
|
this.keybinds.altKey === "ShiftRight"
|
|
) {
|
|
return event.shiftKey;
|
|
}
|
|
if (
|
|
this.keybinds.altKey === "MetaLeft" ||
|
|
this.keybinds.altKey === "MetaRight"
|
|
) {
|
|
return event.metaKey;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
isAltKeyPressed(event: PointerEvent): boolean {
|
|
return (
|
|
((this.keybinds.altKey === "AltLeft" ||
|
|
this.keybinds.altKey === "AltRight") &&
|
|
event.altKey) ||
|
|
((this.keybinds.altKey === "ControlLeft" ||
|
|
this.keybinds.altKey === "ControlRight") &&
|
|
event.ctrlKey) ||
|
|
((this.keybinds.altKey === "ShiftLeft" ||
|
|
this.keybinds.altKey === "ShiftRight") &&
|
|
event.shiftKey) ||
|
|
((this.keybinds.altKey === "MetaLeft" ||
|
|
this.keybinds.altKey === "MetaRight") &&
|
|
event.metaKey)
|
|
);
|
|
}
|
|
}
|