made return value not nullable, fixed sequence of keys in events, removed AI text from readme

This commit is contained in:
Ben
2025-08-17 17:07:50 +02:00
parent 093a812b01
commit ccdc0eb828
6 changed files with 40 additions and 30 deletions

View File

@@ -1,7 +1,7 @@
# hyperf-keybinds # hyperf-keybinds
Quickly handle keyboard shortcuts and sequences in your app. Handle keybind sequences in your app.
You can have branches of sequences, the only restriction being that one sequence cannot be a strict subset of another.
## Install ## Install
```bash ```bash
@@ -11,23 +11,30 @@ npm install hyperf-keybinds
## Quick Start ## Quick Start
```ts ```ts
import { createKeyHandler, KeybindEventTypes, ModifierKey } from 'hyperf-keybinds'; import { createKeyHandler, ModifierKey, KeybindEvent} from 'hyperf-keybinds';
// Define a command // Define commands
const commands = [ const commands = [
{ command: [{ key: 'KeyS', modifiers: [ModifierKey.Control] }], callback: () => console.log('Ctrl+S!') }, { command: [{ key: 'KeyS', modifiers: [ModifierKey.Control] }], callback: () => console.log('Ctrl+S!') },
{ command: [{ key: 'KeyA', modifiers: []}, { key: 'KeyS', modifiers: []}], callback: () => console.log('a - s!')} { command: [{ key: 'KeyA', modifiers: []}, { key: 'KeyS', modifiers: []}], callback: () => console.log('a - s!')}
]; ];
// Create handler and emitter // Create handler
const { handler, emitter } = createKeyHandler(commands); const {handler, emitter, success} = createKeyHandler(commands, 5000);
// Attach to window // Success is false if you provided invalid sequences.
if (success)
{
window.addEventListener('keydown', handler); window.addEventListener('keydown', handler);
// Listen to events // Listen to events
emitter.on(e => console.log(e.type)); emitter.on((event : KeybindEvent) => console.log(event.type, event));
}
``` ```
Now Ctrl+S triggers your callback and emits events. Now Ctrl+S triggers your callback and emits events.
Pressing a then s triggers a separate callback. Pressing a then s triggers a separate callback.
Timeout (default 5000) can be observed by just pressing key A.
Key codes can be looked up here: https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values

View File

@@ -1,6 +1,6 @@
{ {
"name": "hyperf-keybinds", "name": "hyperf-keybinds",
"version": "0.1.1", "version": "0.1.2",
"description": "", "description": "",
"main": "dist/index.js", "main": "dist/index.js",

View File

@@ -2,10 +2,14 @@ import { KeybindEmitter } from "./keybindEmitter";
import { KeyTree } from "./keyTree"; import { KeyTree } from "./keyTree";
import { KeybindEventTypes, ModifierKey, type CommandMap, type KeyCommand, type KeyHandlerReturn, type Modifiers } from "./types"; import { KeybindEventTypes, ModifierKey, type CommandMap, type KeyCommand, type KeyHandlerReturn, type Modifiers } from "./types";
export function createKeyHandler(commandMaps : CommandMap[], timeout : number = 5000): KeyHandlerReturn | null { export function createKeyHandler(commandMaps : CommandMap[], timeout : number = 5000): KeyHandlerReturn {
const emitter = new KeybindEmitter(); const emitter = new KeybindEmitter();
const tree = KeyTree.buildTree(commandMaps); const tree = KeyTree.buildTree(commandMaps);
if (tree === null) return null; if (tree === null) return {
handler: () => {},
emitter: emitter,
success: false
};
const sequenceProgress : KeyCommand[] = []; const sequenceProgress : KeyCommand[] = [];
var currentTreeNode : KeyTree | null = null; var currentTreeNode : KeyTree | null = null;
@@ -20,7 +24,7 @@ export function createKeyHandler(commandMaps : CommandMap[], timeout : number =
const tryResetFields = () => { const tryResetFields = () => {
currentTreeNode = null; currentTreeNode = null;
sequenceProgress.length = 0; sequenceProgress.splice(0);
tryResetTimeout(); tryResetTimeout();
}; };
@@ -68,7 +72,7 @@ export function createKeyHandler(commandMaps : CommandMap[], timeout : number =
} }
} }
}; };
return {handler, emitter}; return {handler, emitter, success: true};
} }
function eventToKeyCommand(event: KeyboardEvent): KeyCommand{ function eventToKeyCommand(event: KeyboardEvent): KeyCommand{

View File

@@ -1 +1,2 @@
export { createKeyHandler } from './createKeyHandler'; export { createKeyHandler } from './createKeyHandler';
export * from './types';

View File

@@ -9,21 +9,20 @@ describe("createKeyHandler", () => {
const command = makeCommand("KeyA"); const command = makeCommand("KeyA");
const callback = vi.fn(); const callback = vi.fn();
const keyHandlerReturn = createKeyHandler([
const {handler, emitter, success} = createKeyHandler([
{ {
command: [command], command: [command],
callback: callback callback: callback
} }
]); ]);
expect(keyHandlerReturn).not.toBe(null); expect(success).toBe(true);
const handler = keyHandlerReturn?.handler;
const emitter = keyHandlerReturn?.emitter;
const listener = vi.fn(); const listener = vi.fn();
emitter?.on(listener); emitter.on(listener);
const event = { code: command.key, shiftKey: false, ctrlKey: false, altKey: false, metaKey: false } as KeyboardEvent; const event = { code: command.key, shiftKey: false, ctrlKey: false, altKey: false, metaKey: false } as KeyboardEvent;
handler?.(event); handler(event);
expect(listener).toHaveBeenCalledTimes(2); expect(listener).toHaveBeenCalledTimes(2);
@@ -56,12 +55,11 @@ describe("createKeyHandler", () => {
const command2 = makeCommand("KeyB"); const command2 = makeCommand("KeyB");
const callback = vi.fn(); const callback = vi.fn();
const keyHandlerReturn = createKeyHandler([ const {handler, emitter, success} = createKeyHandler([
{ command: [command1, command2], callback } { command: [command1, command2], callback }
], delay); ], delay);
const handler = keyHandlerReturn?.handler; expect(success).toBe(true);
const emitter = keyHandlerReturn?.emitter;
const listener = vi.fn(); const listener = vi.fn();
emitter?.on(listener); emitter?.on(listener);
@@ -93,12 +91,12 @@ describe("createKeyHandler", () => {
const command = makeCommand("KeyA"); const command = makeCommand("KeyA");
const callback = vi.fn(); const callback = vi.fn();
const keyHandlerReturn = createKeyHandler([ const {handler, emitter, success} = createKeyHandler([
{ command: [command], callback } { command: [command], callback }
]); ]);
const handler = keyHandlerReturn?.handler; expect(success).toBe(true);
const emitter = keyHandlerReturn?.emitter;
const listener = vi.fn(); const listener = vi.fn();
emitter?.on(listener); emitter?.on(listener);
@@ -124,12 +122,11 @@ describe("createKeyHandler", () => {
const command1 = makeCommand("KeyA"); const command1 = makeCommand("KeyA");
const command2 = makeCommand("KeyB"); const command2 = makeCommand("KeyB");
const callback = vi.fn(); const callback = vi.fn();
const keyHandlerReturn = createKeyHandler([ const {handler, emitter, success} = createKeyHandler([
{ command: [command1, command2], callback } { command: [command1, command2], callback }
]); ]);
const handler = keyHandlerReturn?.handler; expect(success).toBe(true);
const emitter = keyHandlerReturn?.emitter;
const listener = vi.fn(); const listener = vi.fn();
emitter?.on(listener); emitter?.on(listener);

View File

@@ -38,4 +38,5 @@ export type KeyEventHandler = (event: KeyboardEvent) => void;
export interface KeyHandlerReturn { export interface KeyHandlerReturn {
handler: KeyEventHandler; handler: KeyEventHandler;
emitter: KeybindEmitter; emitter: KeybindEmitter;
success: boolean;
} }