diff --git a/web/src/engine/osk/src/input/gestures/browser/pendingMultiTap.ts b/web/src/engine/osk/src/input/gestures/browser/pendingMultiTap.ts deleted file mode 100644 index 4f26862e8d8..00000000000 --- a/web/src/engine/osk/src/input/gestures/browser/pendingMultiTap.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { Codes, KeyEvent } from '@keymanapp/keyboard-processor'; -import { type KeyElement } from '../../../keyElement.js'; -import VisualKeyboard from '../../../visualKeyboard.js'; -// import PendingGesture from '../pendingGesture.interface.js'; - -export enum PendingMultiTapState { Waiting, Realized, Cancelled }; -/** - * Implements the multi-tap gesture, which is a series of taps on a single key - * (based on key id substring in the case of the shift key), within a - * specified timeout period. - */ -export default class PendingMultiTap { - public readonly vkbd: VisualKeyboard; - public readonly baseKey: KeyElement; - public readonly count: number; - private timerId; - private _touches = 1; // we start the multitap with a single touch - private _state: PendingMultiTapState = PendingMultiTapState.Waiting; - private _timeout: Promise; - private cancelDelayFactor = 125; // 125msec * count - private _destinationLayerId; - - public get timeout() { - return this._timeout; - } - public get realized() { - return this._state == PendingMultiTapState.Realized; - } - public get cancelled() { - return this._state == PendingMultiTapState.Cancelled; - } - - /** - * Construct a record of a potential multitap gesture - * @param vkbd - * @param baseKey key which is being tapped - * @param count number of taps required to finalize this gesture - */ - constructor(vkbd: VisualKeyboard, baseKey: KeyElement, count: number) { - this.vkbd = vkbd; - this.count = count; - this.baseKey = baseKey; - - this._destinationLayerId = 'caps'; - let multitap = baseKey?.key?.spec?.['multitap']; - if(multitap?.length && multitap[0]?.['nextlayer']) { - this._destinationLayerId = multitap[0]['nextlayer']; - } - - const _this = this; - this._timeout = new Promise(function(resolve) { - // If multiple taps do not occur within the timeout window, - // then we will abandon the gesture - _this.timerId = window.setTimeout(() => { - _this.cancel(); - resolve(); - }, _this.cancelDelayFactor * _this.count); - }); - } - - public static isValidTarget(vkbd: VisualKeyboard, baseKey: KeyElement) { - // Could use String.includes, but Chrome for Android must be version 41+. - // We support down to version 37. - return ( - baseKey['keyId'].indexOf('K_SHIFT') >= 0 && - vkbd.layerGroup.layers['caps'] && - !baseKey['subKeys'] && - vkbd.touchCount == 1 - ); - } - - private cleanup(): void { - if(this.timerId) { - window.clearTimeout(this.timerId); - } - this.timerId = null; - } - - /** - * Cancel a pending multitap gesture - */ - public cancel(): void { - this._state = PendingMultiTapState.Cancelled; - this.cleanup(); - } - - /** - * Increments the touch counter for the gesture, and - * if the touch count is reached, realize the gesture - * @returns new state of the gesture - */ - public incrementTouch(newKey: KeyElement): PendingMultiTapState { - // TODO: support for any key - if(this._state == PendingMultiTapState.Waiting) { - if(!newKey?.['keyId']?.includes('K_SHIFT')) { - this.cancel(); - } - else if(++this._touches == this.count) { - this.realize(); - } - } - return this._state; - } - - /** - * Realize the gesture. In Keyman 15, this supports only - * the Caps double-tap gesture on the Shift key. - */ - public realize(): void { - if(this._state != PendingMultiTapState.Waiting) { - return; - } - this._state = PendingMultiTapState.Realized; - this.cleanup(); - - // In Keyman 15, only the K_SHIFT key supports multi-tap, so we can hack - // in the switch to the caps layer. - // - // TODO: generalize this with double-tap key properties in touch layout - // description. - let e = KeyEvent.constructNullKeyEvent(this.vkbd.device); - e.kNextLayer = this._destinationLayerId; - e.Lstates = Codes.stateBitmasks.CAPS; - e.LmodifierChange = true; - this.vkbd.raiseKeyEvent(e, null); - } -} \ No newline at end of file diff --git a/web/src/engine/osk/src/visualKeyboard.ts b/web/src/engine/osk/src/visualKeyboard.ts index a390dd69e09..b773b098615 100644 --- a/web/src/engine/osk/src/visualKeyboard.ts +++ b/web/src/engine/osk/src/visualKeyboard.ts @@ -40,7 +40,6 @@ import OSKLayer from './keyboard-layout/oskLayer.js'; import OSKLayerGroup from './keyboard-layout/oskLayerGroup.js'; import { LengthStyle, ParsedLengthStyle } from './lengthStyle.js'; import { defaultFontSize, getFontSizeStyle } from './fontSizeUtils.js'; -import PendingMultiTap, { PendingMultiTapState } from './input/gestures/browser/pendingMultiTap.js'; import InternalKeyTip from './input/gestures/browser/keytip.js'; import CommonConfiguration from './config/commonConfiguration.js'; @@ -204,9 +203,6 @@ export default class VisualKeyboard extends EventEmitter implements Ke activeGestures: GestureHandler[] = []; - // Multi-tap gesture management - pendingMultiTap: PendingMultiTap; - // The keyboard object corresponding to this VisualKeyboard. public readonly layoutKeyboard: Keyboard; public readonly layoutKeyboardProperties: KeyboardProperties; @@ -487,7 +483,7 @@ export default class VisualKeyboard extends EventEmitter implements Ke let correctionKeyDistribution: KeyDistribution; if(gestureStage.matchedId == 'multitap') { - // TODO: examine sequence, determine rota-style index to apply; select THAT item instead. + // TODO: determine fat-finger effects to apply. } if(gestureStage.matchedId == 'subkey-select') { @@ -780,110 +776,6 @@ export default class VisualKeyboard extends EventEmitter implements Ke return distributionFromDistanceMaps(rawSqDistances); } - //#region Input handling start - - // /** - // * The main OSK touch start event handler - // * - // * @param {Event} e touch start event object - // * - // */ - // touch(input: InputEventCoordinate) { - // // Identify the key touched - // var t = input.target, key = this.keyTarget(t); - - // // Special function keys need immediate action - // if (is not special key) { - // if (!this.keyPending) { - // this.initGestures(key, input); - // } - // } - // } - - // /** - // * OSK touch release event handler - // * - // * @param {Event} e touch release event object - // * - // **/ - // release(input: InputEventCoordinate): void { - // // Prevent incorrect multi-touch behaviour if native or device popup visible - // var t = this.currentTarget; - - // // Clear repeated backspace if active, preventing 'sticky' behavior. - // this.cancelDelete(); - - // // Multi-Tap - // if (this.pendingMultiTap && this.pendingMultiTap.realized) { - // // Ignore pending key if we've just handled a multitap - // this.pendingMultiTap = null; - - // this.highlightKey(this.keyPending, false); - // this.keyPending = null; - // this.touchPending = null; - - // return; - // } - - // if (this.pendingMultiTap && this.pendingMultiTap.cancelled) { - // this.pendingMultiTap = null; - // } - // } - - // moveCancel(input: InputEventCoordinate): void { - // // Update all gesture tracking. The function returns true if further input processing - // // should be blocked. (Keeps the subkey array operating when the input coordinate has - // // moved outside the OSK's boundaries.) - // if (this.updateGestures(null, this.keyPending, input)) { - // return; - // } - - // this.cancelDelete(); - // } - - // /** - // * OSK touch move event handler - // * - // * @param {Event} e touch move event object - // * - // **/ - // moveOver(input: InputEventCoordinate): void { - // // Shouldn't be possible, but just in case. - // if (this.touchCount == 0) { - // this.cancelDelete(); - // return; - // } - - // // Get touch position - // const x = input.x - window.pageXOffset; - // const y = input.y - window.pageYOffset; - - // // Move target key and highlighting - // this.touchPending = input; - // // Operates on viewport-based coordinates, not page-based. - // var t1 = document.elementFromPoint(x, y); - // const key0 = this.keyPending; - // let key1 = this.keyTarget(t1); // Not only gets base keys, but also gets popup keys! - - // // Cancels if it's a multitouch attempt. - - // // Do not attempt to support reselection of target key for overlapped keystrokes. - // // Perform _after_ ensuring possible sticky keys have been cancelled. - // if (input.activeInputCount > 1) { - // return; - // } - - // // Gesture-updates should probably be a separate call from other touch-move aspects. - - // // Update all gesture tracking. The function returns true if further input processing - // // should be blocked. - // if (this.updateGestures(key1, key0, input)) { - // return; - // } - // } - - //#endregion - /** * Get the current key target from the touch point element within the key * @@ -1477,79 +1369,6 @@ export default class VisualKeyboard extends EventEmitter implements Ke } } - // /** - // * Initializes all supported gestures given a base key and the triggering touch coordinates. - // * @param key The gesture's base key - // * @param touch The starting touch coordinates for the gesture - // * @returns - // */ - // initGestures(key: KeyElement, input: InputEventCoordinate) { - - // if (this.pendingMultiTap) { - // switch (this.pendingMultiTap.incrementTouch(key)) { - // case PendingMultiTapState.Cancelled: - // this.pendingMultiTap = null; - // break; - // case PendingMultiTapState.Realized: - // // Don't initialize any other gestures if the - // // multi tap is realized; we cleanup on touch - // // release because we need to cancel the base - // // key action - // return; - // } - // } - - // if (!this.pendingMultiTap && PendingMultiTap.isValidTarget(this, key)) { - // // We are only going to support double-tap on Shift - // // in Keyman 15, so we pass in the constant count = 2 - // this.pendingMultiTap = new PendingMultiTap(this, key, 2); - // this.pendingMultiTap.timeout.then(() => { - // this.pendingMultiTap = null; - // }); - // } - // } - - // /** - // * Updates all currently-pending and activated gestures. - // * - // * @param currentKey The key currently underneath the most recent touch coordinate - // * @param previousKey The previously-selected key - // * @param input The current mouse or touch coordinate for the gesture - // * @returns true if should fully capture input, false if input should 'fall through'. - // */ - // updateGestures(currentKey: KeyElement, previousKey: KeyElement, input: InputEventCoordinate): boolean { - // let key0 = previousKey; - // let key1 = currentKey; - - // if(!currentKey && this.pendingMultiTap) { - // this.pendingMultiTap.cancel(); - // this.pendingMultiTap = null; - // } - - // // Clear previous key highlighting, allow subkey controller to highlight as appropriate. - // if (this.subkeyGesture) { - // if (key0) { - // key0.key.highlight(false); - // } - // this.subkeyGesture.updateTouch(input); - - // this.keyPending = null; - // this.touchPending = null; - - // return true; - // } - - // this.currentTarget = null; - - // // If there is an active popup menu (which can occur from the previous block), - // // a subkey popup exists; do not allow base key output. - // if (this.subkeyGesture || this.pendingSubkey) { - // return true; - // } - - // return false; - // } - optionKey(e: KeyElement, keyName: string, keyDown: boolean) { if (keyName.indexOf('K_LOPT') >= 0) { this.emit('globekey', e, keyDown);