diff --git a/web/source/kmwembedded.ts b/web/source/kmwembedded.ts index aa9536b608..af8881627a 100644 --- a/web/source/kmwembedded.ts +++ b/web/source/kmwembedded.ts @@ -429,7 +429,7 @@ namespace com.keyman.text { // While we can't source the base KeyEvent properties for embedded subkeys the same way as native, // we can handle many other pre-processing steps the same way with this common method. - processor.commonClickEventPreprocessing(Lkc); + processor.setSyntheticEventDefaults(Lkc); //if(!Lkc.Lcode) return false; // Value is now zero if not known (Build 347) //Build 353: revert to prior test to try to fix lack of KMEI output, May 1, 2014 diff --git a/web/source/osk/preProcessor.ts b/web/source/osk/preProcessor.ts new file mode 100644 index 0000000000..cb11d21759 --- /dev/null +++ b/web/source/osk/preProcessor.ts @@ -0,0 +1,105 @@ +namespace com.keyman.osk { + export class PreProcessor { + static _GetClickEventProperties(e: osk.ActiveKey, Lelem: HTMLElement): text.KeyEvent { + let keyman = com.keyman.singleton; + let processor = keyman.textProcessor; + + var activeKeyboard = processor.activeKeyboard; + let formFactor = keyman.util.device.formFactor; + + // Get key name and keyboard shift state (needed only for default layouts and physical keyboard handling) + // Note - virtual keys should be treated case-insensitive, so we force uppercasing here. + var layer = e.layer || e.displayLayer || '', keyName=e.id.toUpperCase(); + + // Start: mirrors _GetKeyEventProperties + + // Override key shift state if specified for key in layout (corrected for popup keys KMEW-93) + var keyShiftState = processor.getModifierState(layer); + + // First check the virtual key, and process shift, control, alt or function keys + var Lkc: text.KeyEvent = { + Ltarg: text.Processor.getOutputTarget(Lelem), + Lmodifiers: keyShiftState, + Lstates: 0, + Lcode: text.Codes.keyCodes[keyName], + LisVirtualKey: true, + vkCode: 0, + kName: keyName, + kLayer: layer, + kbdLayer: e.displayLayer, + kNextLayer: e.nextlayer + }; + + // If it's actually a state key modifier, trigger its effects immediately, as KeyboardEvents would do the same. + switch(keyName) { + case 'K_CAPS': + case 'K_NUMLOCK': + case 'K_SCROLL': + processor.stateKeys[keyName] = ! processor.stateKeys[keyName]; + } + + // Performs common pre-analysis for both 'native' and 'embedded' OSK key & subkey input events. + processor.setSyntheticEventDefaults(Lkc); + + // End - mirrors _GetKeyEventProperties + + // Include *limited* support for mnemonic keyboards (Sept 2012) + // If a touch layout has been defined for a mnemonic keyout, do not perform mnemonic mapping for rules on touch devices. + if(activeKeyboard && activeKeyboard.isMnemonic && !(activeKeyboard.layouts && formFactor != 'desktop')) { + if(Lkc.Lcode != text.Codes.keyCodes['K_SPACE']) { // exception required, March 2013 + // Jan 2019 - interesting that 'K_SPACE' also affects the caps-state check... + Lkc.vkCode = Lkc.Lcode; + text.Processor.setMnemonicCode(Lkc, layer.indexOf('shift') != -1, processor.stateKeys['K_CAPS']); + } + } else { + Lkc.vkCode=Lkc.Lcode; + } + + // Support version 1.0 KeymanWeb keyboards that do not define positional vs mnemonic + if(!activeKeyboard.definesPositionalOrMnemonic) { + Lkc.Lcode = KeyMapping._USKeyCodeToCharCode(Lkc); + Lkc.LisVirtualKey=false; + } + + return Lkc; + } + + /** + * Simulate a keystroke according to the touched keyboard button element + * + * Note that the test-case oriented 'recorder' stubs this method to facilitate OSK-based input + * recording for use in test cases. If changing this function, please ensure the recorder is + * not affected. + * + * @param {Object} e element touched (or clicked) + */ + static clickKey(e: osk.KeyElement, touch?: Touch, layerId?: string, keyDistribution?: text.KeyDistribution) { + let keyman = com.keyman.singleton; + var Lelem = keyman.domManager.getLastActiveElement(); + + if(Lelem != null) { + // Handle any DOM state management related to click inputs. + let outputTarget = text.Processor.getOutputTarget(Lelem); + keyman.domManager.initActiveElement(Lelem); + + // Turn off key highlighting (or preview) + keyman['osk'].vkbd.highlightKey(e,false); + + // Clear any cached codepoint data; we can rebuild it if it's unchanged. + outputTarget.invalidateSelection(); + // Deadkey matching continues to be troublesome. + // Deleting matched deadkeys here seems to correct some of the issues. (JD 6/6/14) + outputTarget.deadkeys().deleteMatched(); // Delete any matched deadkeys before continuing + + let Lkc = PreProcessor._GetClickEventProperties(e['key'].spec as osk.ActiveKey, Lelem); + if(keyman.modelManager.enabled) { + Lkc.source = touch; + Lkc.keyDistribution = keyDistribution; + } + return keyman.textProcessor.processKeyEvent(Lkc, e); + } else { + return true; + } + } + } +} \ No newline at end of file diff --git a/web/source/osk/visualKeyboard.ts b/web/source/osk/visualKeyboard.ts index 57b619ab63..0fbe396661 100644 --- a/web/source/osk/visualKeyboard.ts +++ b/web/source/osk/visualKeyboard.ts @@ -1,5 +1,6 @@ /// /// +/// namespace com.keyman.osk { let Codes = com.keyman.text.Codes; @@ -911,7 +912,6 @@ namespace com.keyman.osk { * */ touch: (e: TouchEvent) => void = function(this: VisualKeyboard, e: TouchEvent) { - let Processor = com.keyman.singleton.textProcessor; // Identify the key touched var t = e.changedTouches[0].target, key = this.keyTarget(t); @@ -952,7 +952,7 @@ namespace com.keyman.osk { // Special function keys need immediate action if(keyName == 'K_LOPT' || keyName == 'K_ROPT') { window.setTimeout(function(this: VisualKeyboard){ - Processor.clickKey(key); + PreProcessor.clickKey(key); }.bind(this),0); this.keyPending = null; this.touchPending = null; @@ -962,7 +962,7 @@ namespace com.keyman.osk { let touchProbabilities = this.getTouchProbabilities(e.changedTouches[0]); // While we could inline the execution of the delete key here, we lose the ability to // record the backspace key if we do so. - Processor.clickKey(key, e.changedTouches[0], this.layerId, touchProbabilities); + PreProcessor.clickKey(key, e.changedTouches[0], this.layerId, touchProbabilities); this.deleteKey = key; this.deleting = window.setTimeout(this.repeatDelete,500); this.keyPending = null; @@ -971,7 +971,7 @@ namespace com.keyman.osk { if(this.keyPending) { this.highlightKey(this.keyPending, false); let touchProbabilities = this.getTouchProbabilities(this.touchPending); - Processor.clickKey(this.keyPending, this.touchPending, this.layerId, touchProbabilities); + PreProcessor.clickKey(this.keyPending, this.touchPending, this.layerId, touchProbabilities); this.clearPopup(); // Decrement the number of unreleased touch points to prevent // sending the keystroke again when the key is actually released @@ -1047,7 +1047,7 @@ namespace com.keyman.osk { // Output character unless moved off key if(this.keyPending.className.indexOf('hidden') < 0 && tc > 0 && !beyondEdge) { let touchProbabilities = this.getTouchProbabilities(e.changedTouches[0]); - Processor.clickKey(this.keyPending, e.changedTouches[0], this.layerId, touchProbabilities); + PreProcessor.clickKey(this.keyPending, e.changedTouches[0], this.layerId, touchProbabilities); } this.clearPopup(); this.keyPending = null; @@ -1321,10 +1321,8 @@ namespace com.keyman.osk { * Repeat backspace as long as the backspace key is held down **/ repeatDelete: () => void = function(this: VisualKeyboard) { - let Processor = com.keyman.singleton.textProcessor; - if(this.deleting) { - Processor.clickKey(this.deleteKey); + PreProcessor.clickKey(this.deleteKey); this.deleting = window.setTimeout(this.repeatDelete,100); } }.bind(this); @@ -1763,7 +1761,7 @@ namespace com.keyman.osk { // Process as click if mouse button released anywhere over key if(util.eventType(e) == 'mouseup') { if(key.id == this.currentKey) { - keyman.textProcessor.clickKey(key); + PreProcessor.clickKey(key); } this.currentKey=''; } diff --git a/web/source/recorder_ui_and_stubs.js b/web/source/recorder_ui_and_stubs.js index 1809ad4777..bcb4a82960 100644 --- a/web/source/recorder_ui_and_stubs.js +++ b/web/source/recorder_ui_and_stubs.js @@ -127,15 +127,15 @@ copyTestDefinition = function() { alert("Unable to copy successfully."); } -var _ock = com.keyman.text.Processor.prototype.clickKey; //.bind(keyman.osk); -com.keyman.text.Processor.prototype.clickKey = function(e) { +var _ock = com.keyman.osk.PreProcessor.clickKey; //.bind(keyman.osk); +com.keyman.osk.PreProcessor.clickKey = function(e) { if(com.keyman.dom.DOMEventHandlers.states.activeElement != in_output && com.keyman.dom.DOMEventHandlers.states.activeElement != in_output['kmw_ip']) { - return _ock.call(com.keyman.singleton.textProcessor, e); + return _ock(e); } var event = new KMWRecorder.OSKInputEvent(e); - var retVal = _ock.call(com.keyman.singleton.textProcessor, e); + var retVal = _ock(e); // Record the click/touch as part of a test sequence! addInputRecord(event); diff --git a/web/source/text/processor.ts b/web/source/text/processor.ts index 0406e142e0..7b9c71e2ad 100644 --- a/web/source/text/processor.ts +++ b/web/source/text/processor.ts @@ -178,70 +178,7 @@ namespace com.keyman.text { } } - _GetClickEventProperties(e: osk.ActiveKey, Lelem: HTMLElement): KeyEvent { - let keyman = com.keyman.singleton; - - var activeKeyboard = this.activeKeyboard; - let formFactor = keyman.util.device.formFactor; - - // Get key name and keyboard shift state (needed only for default layouts and physical keyboard handling) - // Note - virtual keys should be treated case-insensitive, so we force uppercasing here. - var layer = e.layer || e.displayLayer || '', keyName=e.id.toUpperCase(); - - // Start: mirrors _GetKeyEventProperties - - // Override key shift state if specified for key in layout (corrected for popup keys KMEW-93) - var keyShiftState = this.getModifierState(layer); - - // First check the virtual key, and process shift, control, alt or function keys - var Lkc: KeyEvent = { - Ltarg: Processor.getOutputTarget(Lelem), - Lmodifiers: keyShiftState, - Lstates: 0, - Lcode: Codes.keyCodes[keyName], - LisVirtualKey: true, - vkCode: 0, - kName: keyName, - kLayer: layer, - kbdLayer: e.displayLayer, - kNextLayer: e.nextlayer - }; - - // If it's actually a state key modifier, trigger its effects immediately, as KeyboardEvents would do the same. - switch(keyName) { - case 'K_CAPS': - case 'K_NUMLOCK': - case 'K_SCROLL': - this.stateKeys[keyName] = ! this.stateKeys[keyName]; - } - - // Performs common pre-analysis for both 'native' and 'embedded' OSK key & subkey input events. - this.commonClickEventPreprocessing(Lkc); - - // End - mirrors _GetKeyEventProperties - - // Include *limited* support for mnemonic keyboards (Sept 2012) - // If a touch layout has been defined for a mnemonic keyout, do not perform mnemonic mapping for rules on touch devices. - if(activeKeyboard && activeKeyboard.isMnemonic && !(activeKeyboard.layouts && formFactor != 'desktop')) { - if(Lkc.Lcode != Codes.keyCodes['K_SPACE']) { // exception required, March 2013 - // Jan 2019 - interesting that 'K_SPACE' also affects the caps-state check... - Lkc.vkCode = Lkc.Lcode; - Processor.setMnemonicCode(Lkc, layer.indexOf('shift') != -1, this.stateKeys['K_CAPS']); - } - } else { - Lkc.vkCode=Lkc.Lcode; - } - - // Support version 1.0 KeymanWeb keyboards that do not define positional vs mnemonic - if(!activeKeyboard.definesPositionalOrMnemonic) { - Lkc.Lcode = KeyMapping._USKeyCodeToCharCode(Lkc); - Lkc.LisVirtualKey=false; - } - - return Lkc; - } - - commonClickEventPreprocessing(Lkc: KeyEvent) { + setSyntheticEventDefaults(Lkc: text.KeyEvent) { // Set the flags for the state keys. Lkc.Lstates |= this.stateKeys['K_CAPS'] ? Codes.modifierCodes['CAPS'] : Codes.modifierCodes['NO_CAPS']; Lkc.Lstates |= this.stateKeys['K_NUMLOCK'] ? Codes.modifierCodes['NUM_LOCK'] : Codes.modifierCodes['NO_NUM_LOCK']; @@ -433,7 +370,7 @@ namespace com.keyman.text { continue; } - let altEvent = this._GetClickEventProperties(altKey, keyEvent.Ltarg.getElement()); + let altEvent = osk.PreProcessor._GetClickEventProperties(altKey, keyEvent.Ltarg.getElement()); altEvent.Ltarg = mock; let alternateBehavior = this.processKeystroke(altEvent, mock, fromOSK); if(alternateBehavior) { @@ -518,44 +455,6 @@ namespace com.keyman.text { return ruleBehavior == null; } - /** - * Simulate a keystroke according to the touched keyboard button element - * - * Note that the test-case oriented 'recorder' stubs this method to facilitate OSK-based input - * recording for use in test cases. If changing this function, please ensure the recorder is - * not affected. - * - * @param {Object} e element touched (or clicked) - */ - clickKey(e: osk.KeyElement, touch?: Touch, layerId?: string, keyDistribution?: KeyDistribution) { - let keyman = com.keyman.singleton; - var Lelem = keyman.domManager.getLastActiveElement(); - - if(Lelem != null) { - // Handle any DOM state management related to click inputs. - let outputTarget = Processor.getOutputTarget(Lelem); - keyman.domManager.initActiveElement(Lelem); - - // Turn off key highlighting (or preview) - keyman['osk'].vkbd.highlightKey(e,false); - - // Clear any cached codepoint data; we can rebuild it if it's unchanged. - outputTarget.invalidateSelection(); - // Deadkey matching continues to be troublesome. - // Deleting matched deadkeys here seems to correct some of the issues. (JD 6/6/14) - outputTarget.deadkeys().deleteMatched(); // Delete any matched deadkeys before continuing - - let Lkc = this._GetClickEventProperties(e['key'].spec as osk.ActiveKey, Lelem); - if(keyman.modelManager.enabled) { - Lkc.source = touch; - Lkc.keyDistribution = keyDistribution; - } - return this.processKeyEvent(Lkc, e); - } else { - return true; - } - } - // FIXME: makes some bad assumptions. static setMnemonicCode(Lkc: KeyEvent, shifted: boolean, capsActive: boolean) { // K_SPACE is not handled by defaultKeyOutput for physical keystrokes unless using touch-aliased elements.