diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2022-06-03 17:11:32 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-03 17:11:32 -0400 |
commit | c966d9b1ebb12386ac876d93f377fe3a470c6976 (patch) | |
tree | faa270fae2c011da8b05056271453f24d77c9d3c | |
parent | e61edc387c1edeca1745c96d163a397b5bf1abdf (diff) |
Touch and pen input updates (#2172)
* Remove unnecessary return
* Move touch start input filtering
* Refactor
* Add scanOnTouchPress
* Add preventPenScrolling
* Rename scanOnPenPress to scanOnPenMove
* Rename scanOnPenRelease to scanOnPenReleaseHover
* Simplify
* Refactor _searchAtFromPen early exit
* Merge _penPointerPressed and _penPointerReleased into a single variable
* Add more options
* Simplify pen pointer coordinates
* Implement scanOnPenPress and scanOnPenRelease
* Implement scanOnTouchRelease
* Fix tests
* Don't search on touch cancel
* Cancel touch if the touch action is used for scrolling or other gestures
* Fix incorrect scroll prevention options being used
* Organize options
* Fix typos
-rw-r--r-- | ext/css/settings.css | 13 | ||||
-rw-r--r-- | ext/data/schemas/options-schema.json | 42 | ||||
-rw-r--r-- | ext/js/data/options-util.js | 16 | ||||
-rw-r--r-- | ext/js/display/display.js | 7 | ||||
-rw-r--r-- | ext/js/language/text-scanner.js | 145 | ||||
-rw-r--r-- | ext/js/pages/settings/scan-inputs-controller.js | 7 | ||||
-rw-r--r-- | ext/settings.html | 36 | ||||
-rw-r--r-- | test/test-options-util.js | 21 |
8 files changed, 216 insertions, 71 deletions
diff --git a/ext/css/settings.css b/ext/css/settings.css index dc8132be..6f1afa00 100644 --- a/ext/css/settings.css +++ b/ext/css/settings.css @@ -1714,9 +1714,12 @@ code.anki-field-marker { .scan-input-prefix-cell[data-property=search-options] { grid-area: 4/2/5/3; } -.scan-input-prefix-cell[data-property=touch-pen-options] { +.scan-input-prefix-cell[data-property=touch-options] { grid-area: 5/2/6/3; } +.scan-input-prefix-cell[data-property=pen-options] { + grid-area: 6/2/7/3; +} .scan-input-content-cell[data-property=include] { grid-area: 1/3/2/4; } @@ -1735,12 +1738,18 @@ code.anki-field-marker { flex-flow: row wrap; align-items: center; } -.scan-input-content-cell[data-property=touch-pen-options] { +.scan-input-content-cell[data-property=touch-options] { grid-area: 5/3/6/4; display: flex; flex-flow: column nowrap; align-items: flex-start; } +.scan-input-content-cell[data-property=pen-options] { + grid-area: 6/3/7/4; + display: flex; + flex-flow: column nowrap; + align-items: flex-start; +} .scan-input-options-cell { padding: 0.25em 0; align-self: start; diff --git a/ext/data/schemas/options-schema.json b/ext/data/schemas/options-schema.json index 279be153..d7e3b5f4 100644 --- a/ext/data/schemas/options-schema.json +++ b/ext/data/schemas/options-schema.json @@ -457,10 +457,15 @@ "searchTerms": true, "searchKanji": true, "scanOnTouchMove": true, + "scanOnTouchPress": true, + "scanOnTouchRelease": false, + "scanOnPenMove": true, "scanOnPenHover": true, + "scanOnPenReleaseHover": false, "scanOnPenPress": true, "scanOnPenRelease": false, - "preventTouchScrolling": false + "preventTouchScrolling": false, + "preventPenScrolling": false } }, { @@ -476,10 +481,15 @@ "searchTerms": true, "searchKanji": true, "scanOnTouchMove": true, + "scanOnTouchPress": true, + "scanOnTouchRelease": false, + "scanOnPenMove": true, "scanOnPenHover": true, + "scanOnPenReleaseHover": false, "scanOnPenPress": true, "scanOnPenRelease": false, - "preventTouchScrolling": true + "preventTouchScrolling": true, + "preventPenScrolling": true } } ], @@ -528,10 +538,12 @@ "searchTerms", "searchKanji", "scanOnTouchMove", + "scanOnTouchPress", + "scanOnPenMove", "scanOnPenHover", - "scanOnPenPress", - "scanOnPenRelease", - "preventTouchScrolling" + "scanOnPenReleaseHover", + "preventTouchScrolling", + "preventPenScrolling" ], "properties": { "showAdvanced": { @@ -550,10 +562,26 @@ "type": "boolean", "default": true }, + "scanOnTouchPress": { + "type": "boolean", + "default": true + }, + "scanOnTouchRelease": { + "type": "boolean", + "default": false + }, + "scanOnPenMove": { + "type": "boolean", + "default": true + }, "scanOnPenHover": { "type": "boolean", "default": true }, + "scanOnPenReleaseHover": { + "type": "boolean", + "default": false + }, "scanOnPenPress": { "type": "boolean", "default": true @@ -565,6 +593,10 @@ "preventTouchScrolling": { "type": "boolean", "default": true + }, + "preventPenScrolling": { + "type": "boolean", + "default": true } } } diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index f19094df..a163580f 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -953,9 +953,25 @@ class OptionsUtil { // Version 19 changes: // Added anki.noteGuiMode. // Added anki.apiKey. + // Renamed scanning.inputs[].options.scanOnPenPress to scanOnPenMove. + // Renamed scanning.inputs[].options.scanOnPenRelease to scanOnPenReleaseHover. + // Added scanning.inputs[].options.scanOnTouchPress. + // Added scanning.inputs[].options.scanOnTouchRelease. + // Added scanning.inputs[].options.scanOnPenPress. + // Added scanning.inputs[].options.scanOnPenRelease. + // Added scanning.inputs[].options.preventPenScrolling. for (const profile of options.profiles) { profile.options.anki.noteGuiMode = 'browse'; profile.options.anki.apiKey = ''; + for (const input of profile.options.scanning.inputs) { + input.options.scanOnPenMove = input.options.scanOnPenPress; + input.options.scanOnPenReleaseHover = input.options.scanOnPenRelease; + input.options.scanOnTouchPress = true; + input.options.scanOnTouchRelease = false; + input.options.scanOnPenPress = input.options.scanOnPenMove; + input.options.scanOnPenRelease = false; + input.options.preventPenScrolling = input.options.preventTouchScrolling; + } } return options; } diff --git a/ext/js/display/display.js b/ext/js/display/display.js index f9153420..923c9dd2 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -1516,10 +1516,15 @@ class Display extends EventDispatcher { searchTerms: true, searchKanji: true, scanOnTouchMove: false, + scanOnTouchPress: false, + scanOnTouchRelease: false, + scanOnPenMove: false, scanOnPenHover: false, + scanOnPenReleaseHover: false, scanOnPenPress: false, scanOnPenRelease: false, - preventTouchScrolling: false + preventTouchScrolling: false, + preventPenScrolling: false } }], deepContentScan: scanningOptions.deepDomScan, diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js index 36091805..978f3d36 100644 --- a/ext/js/language/text-scanner.js +++ b/ext/js/language/text-scanner.js @@ -83,8 +83,7 @@ class TextScanner extends EventDispatcher { this._preventNextMouseDown = false; this._preventNextClick = false; this._preventScroll = false; - this._penPointerPressed = false; - this._penPointerReleased = false; + this._penPointerState = 0; // 0 = not active; 1 = hovering; 2 = touching; 3 = hovering after touching this._pointerIdTypeMap = new Map(); this._canClearSelection = true; @@ -135,8 +134,7 @@ class TextScanner extends EventDispatcher { this._preventNextMouseDown = false; this._preventNextClick = false; this._preventScroll = false; - this._penPointerPressed = false; - this._penPointerReleased = false; + this._penPointerState = 0; this._pointerIdTypeMap.clear(); this._enabledValue = value; @@ -168,10 +166,15 @@ class TextScanner extends EventDispatcher { searchTerms, searchKanji, scanOnTouchMove, + scanOnTouchPress, + scanOnTouchRelease, + scanOnPenMove, scanOnPenHover, + scanOnPenReleaseHover, scanOnPenPress, scanOnPenRelease, - preventTouchScrolling + preventTouchScrolling, + preventPenScrolling } }) => ({ include: this._getInputArray(include), @@ -181,10 +184,15 @@ class TextScanner extends EventDispatcher { searchTerms, searchKanji, scanOnTouchMove, + scanOnTouchPress, + scanOnTouchRelease, + scanOnPenMove, scanOnPenHover, + scanOnPenReleaseHover, scanOnPenPress, scanOnPenRelease, - preventTouchScrolling + preventTouchScrolling, + preventPenScrolling } })); } @@ -515,41 +523,60 @@ class TextScanner extends EventDispatcher { this._primaryTouchIdentifier = identifier; - this._searchAtFromTouchStart(e, x, y); + if (this._pendingLookup) { return; } + + const inputInfo = this._getMatchingInputGroupFromEvent('touch', 'touchStart', e); + if (inputInfo === null || !inputInfo.input.options.scanOnTouchPress) { return; } + + this._searchAtFromTouchStart(x, y, inputInfo); } _onTouchEnd(e) { - if ( - this._primaryTouchIdentifier === null || - this._getTouch(e.changedTouches, this._primaryTouchIdentifier) === null - ) { - return; - } + if (this._primaryTouchIdentifier === null) { return; } + + const primaryTouch = this._getTouch(e.changedTouches, this._primaryTouchIdentifier); + if (primaryTouch === null) { return; } - this._onPrimaryTouchEnd(); + const {clientX, clientY} = primaryTouch; + this._onPrimaryTouchEnd(e, clientX, clientY, true); } - _onPrimaryTouchEnd() { + _onPrimaryTouchEnd(e, x, y, allowSearch) { this._primaryTouchIdentifier = null; this._preventScroll = false; this._preventNextClick = false; // Don't revert context menu and mouse down prevention, since these events can occur after the touch has ended. // I.e. this._preventNextContextMenu and this._preventNextMouseDown should not be assigned to false. + + if (!allowSearch) { return; } + + const inputInfo = this._getMatchingInputGroupFromEvent('touch', 'touchEnd', e); + if (inputInfo === null || !inputInfo.input.options.scanOnTouchRelease) { return; } + + this._searchAtFromTouchEnd(x, y, inputInfo); } _onTouchCancel(e) { - this._onTouchEnd(e); + if (this._primaryTouchIdentifier === null) { return; } + + const primaryTouch = this._getTouch(e.changedTouches, this._primaryTouchIdentifier); + if (primaryTouch === null) { return; } + + this._onPrimaryTouchEnd(e, 0, 0, false); } _onTouchMove(e) { - if (!this._preventScroll || !e.cancelable || this._primaryTouchIdentifier === null) { + if (this._primaryTouchIdentifier === null) { return; } + + if (!e.cancelable) { + this._onPrimaryTouchEnd(e, 0, 0, false); return; } + if (!this._preventScroll) { return; } + const primaryTouch = this._getTouch(e.changedTouches, this._primaryTouchIdentifier); - if (primaryTouch === null) { - return; - } + if (primaryTouch === null) { return; } const inputInfo = this._getMatchingInputGroupFromEvent('touch', 'touchMove', e); if (inputInfo === null) { return; } @@ -652,7 +679,7 @@ class TextScanner extends EventDispatcher { _onTouchPointerDown(e) { const {clientX, clientY, pointerId} = e; - return this._onPrimaryTouchStart(e, clientX, clientY, pointerId); + this._onPrimaryTouchStart(e, clientX, clientY, pointerId); } _onTouchPointerMove(e) { @@ -666,12 +693,13 @@ class TextScanner extends EventDispatcher { this._searchAt(e.clientX, e.clientY, inputInfo); } - _onTouchPointerUp() { - return this._onPrimaryTouchEnd(); + _onTouchPointerUp(e) { + const {clientX, clientY} = e; + return this._onPrimaryTouchEnd(e, clientX, clientY, true); } - _onTouchPointerCancel() { - return this._onPrimaryTouchEnd(); + _onTouchPointerCancel(e) { + return this._onPrimaryTouchEnd(e, 0, 0, false); } _onTouchPointerOut() { @@ -689,25 +717,24 @@ class TextScanner extends EventDispatcher { } _onPenPointerOver(e) { - this._penPointerPressed = false; - this._penPointerReleased = false; - this._searchAtFromPen(e, e.clientX, e.clientY, 'pointerOver', false); + this._penPointerState = 1; + this._searchAtFromPen(e, 'pointerOver', false); } _onPenPointerDown(e) { - this._penPointerPressed = true; - this._searchAtFromPen(e, e.clientX, e.clientY, 'pointerDown', true); + this._penPointerState = 2; + this._searchAtFromPen(e, 'pointerDown', true); } _onPenPointerMove(e) { - if (this._penPointerPressed && (!this._preventScroll || !e.cancelable)) { return; } - this._searchAtFromPen(e, e.clientX, e.clientY, 'pointerMove', true); + if (this._penPointerState === 2 && (!this._preventScroll || !e.cancelable)) { return; } + this._searchAtFromPen(e, 'pointerMove', true); } - _onPenPointerUp() { - this._penPointerPressed = false; - this._penPointerReleased = true; + _onPenPointerUp(e) { + this._penPointerState = 3; this._preventScroll = false; + this._searchAtFromPen(e, 'pointerUp', false); } _onPenPointerCancel(e) { @@ -715,8 +742,7 @@ class TextScanner extends EventDispatcher { } _onPenPointerOut() { - this._penPointerPressed = false; - this._penPointerReleased = false; + this._penPointerState = 0; this._preventScroll = false; this._preventNextContextMenu = false; this._preventNextMouseDown = false; @@ -953,12 +979,7 @@ class TextScanner extends EventDispatcher { await this._searchAt(x, y, inputInfo); } - async _searchAtFromTouchStart(e, x, y) { - if (this._pendingLookup) { return; } - - const inputInfo = this._getMatchingInputGroupFromEvent('touch', 'touchStart', e); - if (inputInfo === null) { return; } - + async _searchAtFromTouchStart(x, y, inputInfo) { const textSourceCurrentPrevious = this._textSourceCurrent !== null ? this._textSourceCurrent.clone() : null; const preventScroll = inputInfo.input.options.preventTouchScrolling; @@ -974,23 +995,22 @@ class TextScanner extends EventDispatcher { } } - async _searchAtFromPen(e, x, y, eventType, prevent) { + async _searchAtFromTouchEnd(x, y, inputInfo) { + await this._searchAt(x, y, inputInfo); + } + + async _searchAtFromPen(e, eventType, prevent) { if (this._pendingLookup) { return; } const inputInfo = this._getMatchingInputGroupFromEvent('pen', eventType, e); if (inputInfo === null) { return; } - const {input: {options}} = inputInfo; - if ( - (!options.scanOnPenRelease && this._penPointerReleased) || - !(this._penPointerPressed ? options.scanOnPenPress : options.scanOnPenHover) - ) { - return; - } + const {options} = inputInfo.input; + if (!this._isPenEventSupported(eventType, options)) { return; } - const preventScroll = inputInfo.input.options.preventTouchScrolling; + const preventScroll = options.preventPenScrolling; - await this._searchAt(x, y, inputInfo); + await this._searchAt(e.clientX, e.clientY, inputInfo); if ( prevent && @@ -1003,6 +1023,25 @@ class TextScanner extends EventDispatcher { } } + _isPenEventSupported(eventType, options) { + switch (eventType) { + case 'pointerDown': + return options.scanOnPenPress; + case 'pointerUp': + return options.scanOnPenRelease; + } + switch (this._penPointerState) { + case 1: // hovering + return options.scanOnPenHover; + case 2: // touching + return options.scanOnPenMove; + case 3: // hovering after touching + return options.scanOnPenReleaseHover; + default: // not active + return false; + } + } + _getMatchingInputGroupFromEvent(pointerType, eventType, event) { const modifiers = DocumentUtil.getActiveModifiersAndButtons(event); const modifierKeys = DocumentUtil.getActiveModifiers(event); diff --git a/ext/js/pages/settings/scan-inputs-controller.js b/ext/js/pages/settings/scan-inputs-controller.js index 7b363b9a..855ccf9a 100644 --- a/ext/js/pages/settings/scan-inputs-controller.js +++ b/ext/js/pages/settings/scan-inputs-controller.js @@ -150,10 +150,15 @@ class ScanInputsController { searchTerms: true, searchKanji: true, scanOnTouchMove: true, + scanOnTouchPress: true, + scanOnTouchRelease: false, + scanOnPenMove: true, scanOnPenHover: true, + scanOnPenReleaseHover: false, scanOnPenPress: true, scanOnPenRelease: false, - preventTouchScrolling: true + preventTouchScrolling: true, + preventPenScrolling: true } }; } diff --git a/ext/settings.html b/ext/settings.html index 64246fd6..ec9dd34b 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -2934,16 +2934,28 @@ </label> </div> - <div class="scan-input-prefix-cell scan-input-options-cell scan-input-advanced-only" data-property="touch-pen-options"><span>Touch & pen:</span></div> - <div class="scan-input-content-cell scan-input-options-cell scan-input-advanced-only" data-property="touch-pen-options"> + <div class="scan-input-prefix-cell scan-input-options-cell scan-input-advanced-only" data-property="touch-options"><span>Touch options:</span></div> + <div class="scan-input-content-cell scan-input-options-cell scan-input-advanced-only" data-property="touch-options"> + <label class="scan-input-checkbox-item"> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnTouchPress"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Scan on touch press</span> + </label> + <label class="scan-input-checkbox-item"> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnTouchRelease"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Scan on touch release</span> + </label> <label class="scan-input-checkbox-item"> <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnTouchMove"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> <span>Scan on touch move</span> </label> <label class="scan-input-checkbox-item"> - <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnPenHover"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> - <span>Scan on pen hover</span> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.preventTouchScrolling"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Prevent touch scrolling</span> </label> + </div> + + <div class="scan-input-prefix-cell scan-input-options-cell scan-input-advanced-only" data-property="pen-options"><span>Pen options:</span></div> + <div class="scan-input-content-cell scan-input-options-cell scan-input-advanced-only" data-property="pen-options"> <label class="scan-input-checkbox-item"> <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnPenPress"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> <span>Scan on pen press</span> @@ -2953,8 +2965,20 @@ <span>Scan on pen release</span> </label> <label class="scan-input-checkbox-item"> - <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.preventTouchScrolling"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> - <span>Prevent touch/pen scrolling</span> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnPenMove"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Scan on pen move (while touched)</span> + </label> + <label class="scan-input-checkbox-item"> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnPenHover"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Scan on pen hover (before touched)</span> + </label> + <label class="scan-input-checkbox-item"> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.scanOnPenReleaseHover"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Scan on pen hover (after touched)</span> + </label> + <label class="scan-input-checkbox-item"> + <label class="checkbox"><input type="checkbox" class="scan-input-settings-checkbox" data-property="options.preventPenScrolling"><span class="checkbox-body"><span class="checkbox-fill"></span><span class="checkbox-border"></span><span class="checkbox-check"></span></span></label> + <span>Prevent pen scrolling</span> </label> </div> </div> diff --git a/test/test-options-util.js b/test/test-options-util.js index c4f9a3a9..16660fd0 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -367,10 +367,15 @@ function createProfileOptionsUpdatedTestData1() { searchTerms: true, searchKanji: true, scanOnTouchMove: true, + scanOnTouchPress: true, + scanOnTouchRelease: false, + scanOnPenMove: true, scanOnPenHover: true, + scanOnPenReleaseHover: false, scanOnPenPress: true, scanOnPenRelease: false, - preventTouchScrolling: true + preventTouchScrolling: true, + preventPenScrolling: true } }, { @@ -386,10 +391,15 @@ function createProfileOptionsUpdatedTestData1() { searchTerms: true, searchKanji: true, scanOnTouchMove: true, + scanOnTouchPress: true, + scanOnTouchRelease: false, + scanOnPenMove: true, scanOnPenHover: true, + scanOnPenReleaseHover: false, scanOnPenPress: true, scanOnPenRelease: false, - preventTouchScrolling: true + preventTouchScrolling: true, + preventPenScrolling: true } }, { @@ -405,10 +415,15 @@ function createProfileOptionsUpdatedTestData1() { searchTerms: true, searchKanji: true, scanOnTouchMove: true, + scanOnTouchPress: true, + scanOnTouchRelease: false, + scanOnPenMove: true, scanOnPenHover: true, + scanOnPenReleaseHover: false, scanOnPenPress: true, scanOnPenRelease: false, - preventTouchScrolling: true + preventTouchScrolling: true, + preventPenScrolling: true } } ] |