mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-06 07:37:40 +00:00
Merge pull request #16384 from keymanapp/fix/web/cancel-gestures-on-relayout
fix(web): cancel gestures on relayouts and context resets
This commit is contained in:
commit
cafa672d97
3 changed files with 55 additions and 28 deletions
|
|
@ -1,8 +1,22 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by jahorton on 2023-10-16.
|
||||
*
|
||||
* The GestureHandler interface defines methods common to all OSK
|
||||
* gesture-handling classes, providing a common abstraction for common-path
|
||||
* gesture support.
|
||||
*/
|
||||
|
||||
import { ActiveKeyBase, KeyDistribution } from "keyman/engine/keyboard";
|
||||
|
||||
export interface GestureHandler {
|
||||
/**
|
||||
* Triggers cancellation of any further processing for the gesture being handled.
|
||||
* Triggers cancellation of any further processing for the gesture being
|
||||
* handled.
|
||||
*
|
||||
* The method should be able to safely handle the `cancel` method being called
|
||||
* multiple times, much like `clearTimeout` in JS.
|
||||
*/
|
||||
cancel(): void;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,13 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Created by jahorton on 2023-10-04.
|
||||
*
|
||||
* The HeldRepeater class models key input that is repeated when its
|
||||
* corresponding key is held. At this time, the class is mostly used to model a
|
||||
* repeatable Backspace input.
|
||||
*/
|
||||
|
||||
import { GestureSequence } from "keyman/engine/gesture-processor";
|
||||
import { KeyDistribution } from "keyman/engine/keyboard";
|
||||
|
||||
|
|
@ -5,48 +15,47 @@ import { KeyElement } from "../../keyElement.js";
|
|||
import { GestureHandler } from './gestureHandler.js';
|
||||
|
||||
export class HeldRepeater implements GestureHandler {
|
||||
readonly directlyEmitsKeys = true;
|
||||
public readonly directlyEmitsKeys = true;
|
||||
public readonly hasModalVisualization = false;
|
||||
|
||||
static readonly INITIAL_DELAY = 500;
|
||||
static readonly REPEAT_DELAY = 100;
|
||||
public static readonly INITIAL_DELAY = 500; // msec
|
||||
public static readonly REPEAT_DELAY = 100; // msec
|
||||
|
||||
readonly source: GestureSequence<KeyElement, string>;
|
||||
readonly hasModalVisualization = false;
|
||||
readonly repeatClosure: () => void;
|
||||
private readonly source: GestureSequence<KeyElement, string>;
|
||||
private readonly baseKey: KeyElement
|
||||
private readonly actionToRepeat: () => void;
|
||||
private timerHandle: number;
|
||||
|
||||
timerHandle: number;
|
||||
|
||||
constructor(source: GestureSequence<KeyElement, string>, closureToRepeat: () => void) {
|
||||
constructor(source: GestureSequence<KeyElement, string>, actionToRepeat: () => void) {
|
||||
this.source = source;
|
||||
|
||||
const baseKey = source.stageReports[0].item;
|
||||
baseKey.key.highlight(true);
|
||||
this.baseKey = source.stageReports[0].item;
|
||||
this.baseKey.key.highlight(true);
|
||||
this.actionToRepeat = actionToRepeat;
|
||||
|
||||
this.repeatClosure = () => {
|
||||
closureToRepeat();
|
||||
// The repeat-closure may cancel key highlighting. This restores it afterward.
|
||||
baseKey.key.highlight(true);
|
||||
}
|
||||
|
||||
|
||||
this.timerHandle = window.setTimeout(this.deleteRepeater, HeldRepeater.INITIAL_DELAY);
|
||||
this.timerHandle = window.setTimeout(() => this.repeatAction(), HeldRepeater.INITIAL_DELAY);
|
||||
|
||||
this.source.on('complete', () => {
|
||||
window.clearTimeout(this.timerHandle);
|
||||
this.timerHandle = undefined;
|
||||
baseKey.key.highlight(false);
|
||||
this.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.deleteRepeater();
|
||||
if(this.timerHandle !== undefined) {
|
||||
window.clearTimeout(this.timerHandle);
|
||||
delete this.timerHandle;
|
||||
}
|
||||
|
||||
this.baseKey.key.highlight(false);
|
||||
this.source.cancel();
|
||||
}
|
||||
|
||||
readonly deleteRepeater = () => {
|
||||
this.repeatClosure();
|
||||
|
||||
this.timerHandle = window.setTimeout(this.deleteRepeater, HeldRepeater.REPEAT_DELAY);
|
||||
private repeatAction() {
|
||||
this.actionToRepeat();
|
||||
// In case the action to repeat cancels key highlighting, we restore it
|
||||
// afterward.
|
||||
this.baseKey.key.highlight(true);
|
||||
this.timerHandle = window.setTimeout(() => this.repeatAction(), HeldRepeater.REPEAT_DELAY);
|
||||
}
|
||||
|
||||
currentStageKeyDistribution(): KeyDistribution {
|
||||
|
|
|
|||
|
|
@ -1162,6 +1162,10 @@ export class VisualKeyboard extends EventEmitter<EventMap> implements KeyboardVi
|
|||
return;
|
||||
}
|
||||
|
||||
// A re-layout operation can break an ongoing gesture operation.
|
||||
// See #15226 - this is surprisingly relevant for backspaces!
|
||||
this.activeGestures.forEach((g) => g.cancel());
|
||||
|
||||
/*
|
||||
Phase 1: calculations possible at the start without triggering _any_ additional layout reflow.
|
||||
(A single, initial reflow may happen depending on DOM manipulations before this method...,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue