forked from phenom/healer-man
Release Healer Man 0.1.29
This commit is contained in:
1 parent
8c9809d3e0
commit
544c1bee91
120 files changed
+4363
-1036
No files matched your search
@@ -4,6 +4,8 @@ import {
|
||||
emitControllerToken,
|
||||
orderedControllerTokenTransitions,
|
||||
resetControllerState,
|
||||
setExternalControllerMovement,
|
||||
interceptControllerInput,
|
||||
} from "../input/controller";
|
||||
import {
|
||||
MAX_MOUSE_DELTA_PER_EVENT,
|
||||
@@ -23,8 +25,11 @@ import {
|
||||
keyboardCommandForCode,
|
||||
queueJumpRequest,
|
||||
sanitizeMouseDelta,
|
||||
readInputSnapshot,
|
||||
type InputActions,
|
||||
} from "./inputManager";
|
||||
import { normalizeInputPreferences, replaceInputBinding } from "../input/keybinds";
|
||||
import { setCapturingInput } from "../input/keybindRuntime";
|
||||
|
||||
function stubInputEventTargets(): void {
|
||||
const windowTarget = new EventTarget();
|
||||
@@ -59,12 +64,117 @@ function inputActionSpies(blocked = false): InputActions {
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
setCapturingInput(false);
|
||||
endMouseLookDrag();
|
||||
clearJumpRequest();
|
||||
resetControllerState();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
function keyboardEvent(type: "keydown" | "keyup", code: string, modifiers: Partial<KeyboardEvent> = {}) {
|
||||
const event = new Event(type, { cancelable: true });
|
||||
Object.defineProperties(event, Object.fromEntries(Object.entries({ code, target: null, ...modifiers }).map(([key, value]) => [key, { value }])));
|
||||
window.dispatchEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
describe("remappable gameplay controls", () => {
|
||||
it("keeps moving forward when a legacy WoW skill also owns W", () => {
|
||||
stubInputEventTargets();
|
||||
const next = inputActionSpies(); const preferences = normalizeInputPreferences(null);
|
||||
preferences.pc["bar:0:0"] = "KeyW";
|
||||
next.getBindings = (device) => preferences[device];
|
||||
next.desktopActionBarsActive = () => true;
|
||||
next.castDesktopSlot = vi.fn();
|
||||
const dispose = installInput(next);
|
||||
keyboardEvent("keydown", "KeyW");
|
||||
expect(readInputSnapshot().moveForward).toBe(1);
|
||||
expect(next.castDesktopSlot).not.toHaveBeenCalled();
|
||||
keyboardEvent("keyup", "KeyW");
|
||||
expect(readInputSnapshot().moveForward).toBe(0);
|
||||
dispose();
|
||||
});
|
||||
it("honors remapped movement and clears held input when a menu opens", () => {
|
||||
stubInputEventTargets();
|
||||
const next = inputActionSpies(); const preferences = normalizeInputPreferences(null);
|
||||
preferences.pc = replaceInputBinding(preferences.pc, "pc", "move-forward", "ArrowUp");
|
||||
next.getBindings = (device) => preferences[device];
|
||||
const dispose = installInput(next);
|
||||
keyboardEvent("keydown", "KeyW"); expect(readInputSnapshot().moveForward).toBe(0);
|
||||
keyboardEvent("keydown", "ArrowUp");
|
||||
expect(readInputSnapshot()).toMatchObject({ moveForward: 1, lookY: 0 });
|
||||
(next.gameplayActionsBlocked as ReturnType<typeof vi.fn>).mockReturnValue(true);
|
||||
expect(readInputSnapshot().moveForward).toBe(0);
|
||||
(next.gameplayActionsBlocked as ReturnType<typeof vi.fn>).mockReturnValue(false);
|
||||
expect(readInputSnapshot().moveForward).toBe(0);
|
||||
dispose();
|
||||
});
|
||||
it("casts remapped bar chords once and gives ground confirmation its context", () => {
|
||||
stubInputEventTargets();
|
||||
const next = inputActionSpies(); const preferences = normalizeInputPreferences(null);
|
||||
preferences.pc["bar:4:11"] = "Ctrl+Shift+KeyQ";
|
||||
preferences.pc["ground-confirm"] = "Ctrl+Shift+KeyQ";
|
||||
next.getBindings = (device) => preferences[device]; next.desktopActionBarsActive = () => true; next.castDesktopSlot = vi.fn();
|
||||
const dispose = installInput(next);
|
||||
keyboardEvent("keydown", "KeyQ", { ctrlKey: true, shiftKey: true });
|
||||
keyboardEvent("keydown", "KeyQ", { ctrlKey: true, shiftKey: true, repeat: true });
|
||||
expect(next.castDesktopSlot).toHaveBeenCalledExactlyOnceWith(4, 11);
|
||||
(next.groundTargetActive as ReturnType<typeof vi.fn>).mockReturnValue(true);
|
||||
keyboardEvent("keydown", "KeyQ", { ctrlKey: true, shiftKey: true });
|
||||
expect(next.confirmGroundTarget).toHaveBeenCalledTimes(1);
|
||||
expect(next.castDesktopSlot).toHaveBeenCalledTimes(1);
|
||||
dispose();
|
||||
});
|
||||
it("remaps controller axes and buttons with analog movement preserved", () => {
|
||||
stubInputEventTargets();
|
||||
const next = inputActionSpies(); const preferences = normalizeInputPreferences(null);
|
||||
preferences.controller = replaceInputBinding(preferences.controller, "controller", "move-forward", "Axis3-");
|
||||
preferences.controller = replaceInputBinding(preferences.controller, "controller", "move-right", "Button3");
|
||||
next.getBindings = (device) => preferences[device];
|
||||
const dispose = installInput(next);
|
||||
setExternalControllerMovement({ moveX: 0, moveY: -1, lookX: 0, lookY: 0 });
|
||||
expect(readInputSnapshot().moveForward).toBe(0);
|
||||
setExternalControllerMovement({ moveX: 0, moveY: 0, lookX: 0, lookY: -.7 });
|
||||
expect(readInputSnapshot().moveForward).toBeGreaterThan(.3);
|
||||
expect(readInputSnapshot().moveForward).toBeLessThan(1);
|
||||
expect(readInputSnapshot().lookY).toBe(0);
|
||||
setExternalControllerMovement({ moveX: 0, moveY: 0, lookX: 0, lookY: 0 });
|
||||
emitControllerToken({ token: "Button3", repeat: false, pressed: true });
|
||||
expect(readInputSnapshot().moveX).toBe(1);
|
||||
expect(next.castActionBinding).not.toHaveBeenCalled();
|
||||
emitControllerToken({ token: "Button3", repeat: false, pressed: false });
|
||||
expect(readInputSnapshot().moveX).toBe(0);
|
||||
dispose();
|
||||
});
|
||||
it("uses customized controller combinations before their base button", () => {
|
||||
stubInputEventTargets();
|
||||
const next = inputActionSpies(); const preferences = normalizeInputPreferences(null);
|
||||
preferences.controller = replaceInputBinding(preferences.controller, "controller", "jump", "Button8&Button0");
|
||||
next.getBindings = (device) => preferences[device];
|
||||
const dispose = installInput(next);
|
||||
emitControllerToken({ token: "Button8", repeat: false, pressed: true });
|
||||
emitControllerToken({ token: "Button0", repeat: false, pressed: true });
|
||||
expect(consumeJumpRequest()).not.toBeNull();
|
||||
expect(next.castActionBinding).not.toHaveBeenCalled();
|
||||
expect(next.lootActiveBoss).not.toHaveBeenCalled();
|
||||
dispose();
|
||||
});
|
||||
it("blocks keyboard actions, controller actions and movement throughout capture", () => {
|
||||
stubInputEventTargets();
|
||||
const next = inputActionSpies(); const dispose = installInput(next);
|
||||
setCapturingInput(true);
|
||||
const captured = vi.fn(() => true); const unsubscribe = interceptControllerInput(captured);
|
||||
keyboardEvent("keydown", "KeyW"); keyboardEvent("keydown", "KeyI"); keyboardEvent("keydown", "Digit1");
|
||||
emitControllerToken({ token: "Button0", repeat: false, pressed: true });
|
||||
emitControllerToken({ token: "Button9", repeat: false, pressed: true });
|
||||
setExternalControllerMovement({ moveX: 1, moveY: -1, lookX: 0, lookY: 0 });
|
||||
expect(readInputSnapshot()).toMatchObject({ moveX: 0, moveForward: 0 });
|
||||
expect(next.castActionBinding).not.toHaveBeenCalled(); expect(next.toggleInventory).not.toHaveBeenCalled(); expect(next.togglePause).not.toHaveBeenCalled();
|
||||
expect(captured).toHaveBeenCalledTimes(2);
|
||||
unsubscribe(); dispose();
|
||||
});
|
||||
});
|
||||
|
||||
describe("gameplay input bindings", () => {
|
||||
it("consumes custom action keys before movement, menus and legacy action bindings", () => {
|
||||
stubInputEventTargets();
|
||||
|
||||
Reference in new issue
Block a user