From 48cc0e1fc13a296fcfe098eb2ec3381657d903ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sieciechowicz?= Date: Tue, 5 Aug 2025 22:13:56 +0200 Subject: [PATCH] safe-mode for input fields --- .../input/models/devices/input-keyboard.ts | 4 ++- src/lib/modules/input/models/input-action.ts | 10 ++++--- src/lib/modules/input/models/input-device.ts | 13 ++++++++++ .../directives/key-item.directive.ts | 26 ++++++++++++++----- src/public-api.ts | 1 - 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/lib/modules/input/models/devices/input-keyboard.ts b/src/lib/modules/input/models/devices/input-keyboard.ts index 9811a9d..75635b0 100644 --- a/src/lib/modules/input/models/devices/input-keyboard.ts +++ b/src/lib/modules/input/models/devices/input-keyboard.ts @@ -24,7 +24,9 @@ export class InputKeyboard extends InputDevice { private catchKey(event: KeyboardEvent, value: number = 1, angle: number = 0): boolean { const key = event.key; super.setKey(key, value, angle); - event.preventDefault(); + if (!InputDevice.IsKeyEventSafeModeEnabled) { + event.preventDefault(); + } return false; } } diff --git a/src/lib/modules/input/models/input-action.ts b/src/lib/modules/input/models/input-action.ts index c176acb..dc91aaa 100644 --- a/src/lib/modules/input/models/input-action.ts +++ b/src/lib/modules/input/models/input-action.ts @@ -1,6 +1,7 @@ +import { InputDevice } from "./input-device"; import { InputScheme } from "./input-scheme"; -export type ActionCallback = (value: number, data: unknown, angle?:number, timePressed?: number) => void; +export type ActionCallback = (value: number, data: unknown, angle?:number, timePressed?: number, safeMode?: boolean) => void; export class InputAction { @@ -23,14 +24,15 @@ export class InputAction { public fire(value: number, data: unknown = undefined, angle?: number, timePressed?: number) { const isPressed = value > 0; const wasPressed = this.currentValue > 0; + const safeMode = InputDevice.IsKeyEventSafeModeEnabled; if (isPressed !== wasPressed) { if (isPressed) { - this.downActions.forEach(action => action(value, data, angle, timePressed)); + this.downActions.forEach(action => action(value, data, angle, timePressed, safeMode)); } else { - this.upActions.forEach(action => action(value, data, angle, timePressed)); + this.upActions.forEach(action => action(value, data, angle, timePressed, safeMode)); } } else { - this.changeActions.forEach(action => action(value, data, angle, timePressed)); + this.changeActions.forEach(action => action(value, data, angle, timePressed, safeMode)); } this.currentValue = value; diff --git a/src/lib/modules/input/models/input-device.ts b/src/lib/modules/input/models/input-device.ts index 97f23be..e087ea0 100644 --- a/src/lib/modules/input/models/input-device.ts +++ b/src/lib/modules/input/models/input-device.ts @@ -1,6 +1,7 @@ import { EventEmitter } from "@angular/core"; import { InputScheme } from "./input-scheme"; import { InputAction } from "./input-action"; +import { InputService } from "../services/input.service"; export interface InputKeyState { key: string | number; @@ -13,6 +14,18 @@ export abstract class InputDevice { protected scheme?: InputScheme; protected keyStates: InputKeyState[] = []; public keyStateChanged = new EventEmitter(); + public static KeyEventSafeModeEnabled = false; + + public static get IsKeyEventSafeModeEnabled() { + if ((window as any).KeyEventSafeModeEnabled === true) { + return true; + } + if ((window as any).KeyEventSafeModeEnabled === false) { + return false; + } + + return InputDevice.KeyEventSafeModeEnabled; + } constructor( public readonly name: string, diff --git a/src/lib/modules/navigation/directives/key-item.directive.ts b/src/lib/modules/navigation/directives/key-item.directive.ts index 86a18df..ec05322 100644 --- a/src/lib/modules/navigation/directives/key-item.directive.ts +++ b/src/lib/modules/navigation/directives/key-item.directive.ts @@ -1,4 +1,4 @@ -import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Optional, Host, EventEmitter, Output } from '@angular/core'; +import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Optional, Host, EventEmitter, Output, SimpleChanges } from '@angular/core'; import { KeyItemGroupDirective } from './key-item-group.directive'; export interface ActionBindings { @@ -15,6 +15,7 @@ interface HTMLKeyItemEntryElement extends HTMLElement { keyId: number; active: string; actionBindings: ActionBindings; + isActive: boolean; activate: () => void; deactivate: () => void; focus: () => void; @@ -26,7 +27,7 @@ interface HTMLKeyItemEntryElement extends HTMLElement { standalone: true }) export class KeyItemDirective implements OnInit, OnDestroy { - + @Input() isActive = true; @Input() active = 'active'; @Input() actionBindings: ActionBindings = {}; @Output() activated = new EventEmitter(); @@ -57,13 +58,15 @@ export class KeyItemDirective implements OnInit, OnDestroy { } ngOnInit() { + const that = this; this.element.active = this.active; - this.element.activate = () => this.activated.emit(); - this.element.deactivate = () => this.deactivated.emit(); + this.element.activate = () => that.activated.emit(); + this.element.deactivate = () => that.deactivated.emit(); this.element.keyId = this.id; this.element.actionBindings = this.actionBindings; - this.element.focus = () => this.focused.emit(); - this.element.blur = () => this.blurred.emit(); + this.element.isActive = this.isActive; + this.element.focus = () => that.focused.emit(); + this.element.blur = () => that.blurred.emit(); const position = this.element.getBoundingClientRect(); const item = { element: this.element, @@ -81,6 +84,12 @@ export class KeyItemDirective implements OnInit, OnDestroy { } } + ngOnChanges(changes: SimpleChanges) { + if (changes['isActive']) { + this.element.isActive = this.isActive; + } + } + ngOnDestroy() { const index = KeyItemDirective.allItems.findIndex(item => item.element.keyId === this.id); if (index > -1) { @@ -140,13 +149,14 @@ export class KeyItemDirective implements OnInit, OnDestroy { } } if (current) { - const list = allItems.map(item => { + const list = allItems.filter(item => item.element.isActive).map(item => { const distance = Math.sqrt(Math.pow(item.top - this.current!.top, 2) + Math.pow(item.left - this.current!.left, 2)); const angle = 90 + Math.atan2(item.top - this.current!.top, item.left - this.current!.left) * 180 / Math.PI; return { item, distance, angle, + isActive: item.element.isActive, }; }) .filter(item => { @@ -169,12 +179,14 @@ export class KeyItemDirective implements OnInit, OnDestroy { } static SetCurrentItem(item?: KeyItemEntry) { + console.log('KeyItemDirective.SetCurrentItem', {item}); if (this.current?.element.active && this.current.element.classList.contains(this.current.element.active)) { this.current.element.classList.remove(this.current.element.active); } this.current?.element.blur(); this.current = item; this.current?.element.focus(); + console.log({focus: this.current?.element.focus.toString()}); if (this.current?.element.active && !this.current.element.classList.contains(this.current.element.active)) { this.current.element.classList.add(this.current.element.active); } diff --git a/src/public-api.ts b/src/public-api.ts index ee8aeb5..c0be3f8 100644 --- a/src/public-api.ts +++ b/src/public-api.ts @@ -12,7 +12,6 @@ export * from './lib/modules/input/models/devices/input-gamepad'; export * from './lib/modules/input/models/devices/input-keyboard'; - export * from './lib/modules/navigation/navigation-module'; export * from './lib/modules/navigation/directives/action-binding.directive';