mirror of
https://github.com/penpot/penpot.git
synced 2026-10-31 15:00:32 +00:00
Fixes the problems found after #12326 and listed in #12327. Mousetrap now tries several names for each key press, in order, and fires the first one with a binding: letters and digits by keyCode when a modifier is held, punctuation by position (layout map, or a US table when the browser has none), the typed glyph, and the typed glyph without the Shift it needed. With AltGr the typed glyph comes before the position. The shortcut recorder asks Mousetrap for the key it stores, so a recorded shortcut always fires. This makes "?" and "+" work on every layout, Shift and Ctrl+Shift with punctuation work in Firefox and Safari, Option+letter work on macOS, and AltGr+º hide the UI on Linux with a Spanish layout. Chrome on Linux returns the map of the first configured layout, not the active one. Mousetrap now drops the map when an unmodified punctuation key types something else. The layout twins are no longer needed and are removed: "shift+'" made "?" zoom to the selection on Spanish layouts. The Add node shortcut is removed too: on US layouts its key is the "+" zoom key, and on Firefox with a Spanish layout it cannot fire. The Firefox and Safari warning in the shortcuts settings is gone, since those shortcuts now work there. The user guide and translations follow these changes. AI-assisted-by: claude-opus-5-5
95 lines
3.4 KiB
JavaScript
95 lines
3.4 KiB
JavaScript
import { describe, it } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { freshInstance, fire, makeKeyEvent } from "./helpers.js";
|
|
|
|
function fired(bindStr, eventOver) {
|
|
const { mousetrap, target } = freshInstance();
|
|
let calls = 0;
|
|
mousetrap.bind(bindStr, () => {
|
|
calls++;
|
|
});
|
|
fire(target, makeKeyEvent(eventOver));
|
|
return calls;
|
|
}
|
|
|
|
describe("modifiers", () => {
|
|
it("matches each flag on its own", () => {
|
|
assert.equal(fired("shift+x", { key: "x", code: "KeyX", shiftKey: true }), 1);
|
|
assert.equal(fired("alt+x", { key: "x", code: "KeyX", altKey: true }), 1);
|
|
assert.equal(fired("ctrl+x", { key: "x", code: "KeyX", ctrlKey: true }), 1);
|
|
assert.equal(fired("meta+x", { key: "x", code: "KeyX", metaKey: true }), 1);
|
|
});
|
|
|
|
it("does not fire without the bound modifier", () => {
|
|
assert.equal(fired("shift+x", { key: "x", code: "KeyX" }), 0);
|
|
assert.equal(fired("ctrl+x", { key: "x", code: "KeyX", altKey: true }), 0);
|
|
});
|
|
|
|
it("combines modifiers regardless of bind order", () => {
|
|
const event = { key: "q", code: "KeyQ", ctrlKey: true, altKey: true, shiftKey: true };
|
|
assert.equal(fired("ctrl+alt+shift+q", event), 1);
|
|
assert.equal(fired("shift+ctrl+alt+q", event), 1);
|
|
});
|
|
|
|
it("drops the phantom ctrl and alt while AltGraph is active", () => {
|
|
const altgr = {
|
|
key: "]",
|
|
code: "BracketRight",
|
|
ctrlKey: true,
|
|
altKey: true,
|
|
getModifierState: (mod) => mod === "AltGraph",
|
|
};
|
|
assert.equal(fired("ctrl+alt+]", altgr), 0);
|
|
assert.equal(fired("alt+]", altgr), 0);
|
|
assert.equal(fired("]", altgr), 1);
|
|
});
|
|
|
|
it("falls back to ctrl+alt for a letter that AltGr turns into a glyph", () => {
|
|
// Spanish layout on Windows: Ctrl+Alt+E types "€".
|
|
const event = {
|
|
key: "€",
|
|
code: "KeyE",
|
|
keyCode: 69,
|
|
ctrlKey: true,
|
|
altKey: true,
|
|
getModifierState: (mod) => mod === "AltGraph",
|
|
};
|
|
assert.equal(fired("ctrl+alt+e", event), 1);
|
|
assert.equal(fired("€", event), 1);
|
|
});
|
|
|
|
it("matches letters and digits by keyCode when a modifier changes the glyph", () => {
|
|
// Shift+1 types "!" on US and Spanish layouts.
|
|
assert.equal(fired("shift+1", { key: "!", code: "Digit1", keyCode: 49, shiftKey: true }), 1);
|
|
// Spanish layout: Shift+0 types "=".
|
|
assert.equal(fired("shift+0", { key: "=", code: "Digit0", keyCode: 48, shiftKey: true }), 1);
|
|
// macOS: Option+M types "µ" and Option+E is a dead key.
|
|
assert.equal(fired("alt+m", { key: "µ", code: "KeyM", keyCode: 77, altKey: true }), 1);
|
|
assert.equal(fired("alt+e", { key: "Dead", code: "KeyE", keyCode: 69, altKey: true }), 1);
|
|
assert.equal(fired("alt+shift+5", { key: "%", code: "Digit5", keyCode: 53, altKey: true, shiftKey: true }), 1);
|
|
});
|
|
|
|
it("keeps AZERTY letters by layout, not by position", () => {
|
|
// AZERTY: the key at the US "W" position types "z" and has keyCode 90.
|
|
assert.equal(fired("ctrl+z", { key: "z", code: "KeyW", keyCode: 90, ctrlKey: true }), 1);
|
|
});
|
|
|
|
it("keeps a real ctrl+alt without AltGraph", () => {
|
|
const event = {
|
|
key: "]",
|
|
code: "BracketRight",
|
|
ctrlKey: true,
|
|
altKey: true,
|
|
getModifierState: () => false,
|
|
};
|
|
assert.equal(fired("ctrl+alt+]", event), 1);
|
|
});
|
|
|
|
it("works when the event has no getModifierState at all", () => {
|
|
assert.equal(
|
|
fired("ctrl+x", { key: "x", code: "KeyX", ctrlKey: true, getModifierState: undefined }),
|
|
1,
|
|
);
|
|
});
|
|
});
|