diff --git a/web/source/osk/activeLayout.ts b/web/source/osk/activeLayout.ts index 6be313d397..e4a0289b65 100644 --- a/web/source/osk/activeLayout.ts +++ b/web/source/osk/activeLayout.ts @@ -311,6 +311,10 @@ namespace com.keyman.osk { // generating a probability distribution. this.row.forEach(function(row: ActiveRow): void { row.key.forEach(function(key: ActiveKey): void { + // If the key lacks an ID, just skip it. Sometimes used for padding. + if(!key.id) { + return; + } // These represent the within-key distance of the touch from the key's center. // Both should be on the interval [0, 0.5]. let dx = Math.abs(touchCoords.x - key.proportionalX); @@ -361,9 +365,9 @@ namespace com.keyman.osk { // Keys usually are specified in a "long form" prefixed with their layer's ID. if(keyId.indexOf(this.id + '-') == 0) { keyId = keyId.replace(this.id + '-', ''); - - return this.keyMap[keyId]; } + + return this.keyMap[keyId]; } } @@ -371,10 +375,19 @@ namespace com.keyman.osk { layer: ActiveLayer[]; font: string; + /** + * Facilitates mapping layer id strings to their specification objects. + */ + layerMap: {[layerId: string]: ActiveLayer}; + private constructor() { } + getLayer(layerId: string): ActiveLayer { + return this.layerMap[layerId]; + } + /** * * @param layout @@ -388,6 +401,7 @@ namespace com.keyman.osk { // Create a separate OSK div for each OSK layer, only one of which will ever be visible var n: number, i: number; var layers: LayoutLayer[], layer: LayoutLayer; + let layerMap: {[layerId: string]: ActiveLayer} = {}; var rows: LayoutRow[]; layers=layout['layer']; @@ -409,6 +423,7 @@ namespace com.keyman.osk { for(n=0; n Lelem.base; } - - if (inputEle && (inputEle.type == 'search' || inputEle.type == 'submit')) { - inputEle.disabled=false; - inputEle.form.submit(); - } else { - domManager.moveToNext(false); + if(!disableDOM) { + if (inputEle && (inputEle.type == 'search' || inputEle.type == 'submit')) { + inputEle.disabled=false; + inputEle.form.submit(); + } else { + domManager.moveToNext(false); + } } } break; @@ -302,8 +309,7 @@ namespace com.keyman.text { } } - processKeystroke(keyEvent: KeyEvent, outputTarget: OutputTarget, fromOSK: boolean): boolean { - // Create `Processor.processKeystroke` for this section. + processKeystroke(keyEvent: KeyEvent, outputTarget: OutputTarget, fromOSK: boolean, disableDOM: boolean): boolean { let keyman = com.keyman.singleton; var activeKeyboard = keyman.keyboardManager.activeKeyboard; @@ -333,7 +339,7 @@ namespace com.keyman.text { // Handle unmapped keys, including special keys // The following is physical layout dependent, so should be avoided if possible. All keys should be mapped. - var ch = this.defaultKeyOutput(keyEvent, keyEvent.Lmodifiers, true); + var ch = this.defaultKeyOutput(keyEvent, keyEvent.Lmodifiers, true, disableDOM); if(ch) { kbdInterface.output(0, outputTarget, ch); LeventMatched = 1; @@ -342,7 +348,6 @@ namespace com.keyman.text { } } - /// End serious keystroke processing. return LeventMatched == 1; } @@ -355,7 +360,6 @@ namespace com.keyman.text { */ processKeyEvent(keyEvent: KeyEvent, e?: osk.KeyElement | boolean): boolean { let keyman = com.keyman.singleton; - //var Lelem = keyman.domManager.getLastActiveElement(); let fromOSK = !!e; // If specified, it's from the OSK. @@ -364,8 +368,6 @@ namespace com.keyman.text { e = null as osk.KeyElement; // Cast is necessary for TS type-checking later in the method. } - var activeKeyboard = keyman.keyboardManager.activeKeyboard; - let kbdInterface = keyman.interface; let formFactor = keyman.util.device.formFactor; let keyMapManager = keyman.keyMapManager; @@ -442,9 +444,7 @@ namespace com.keyman.text { let outputTarget = Processor.getOutputTarget(keyEvent.Ltarg); let preInputMock = Mock.from(outputTarget); - // For fat-finger adjustments, we should iterate across the most likely members of the key distribution, - // not just the selected key. - let LeventMatched = this.processKeystroke(keyEvent, outputTarget, fromOSK); + let LeventMatched = this.processKeystroke(keyEvent, outputTarget, fromOSK, false); // End of fat-finger loop section; the rest is post-processing maintenance. @@ -455,7 +455,28 @@ namespace com.keyman.text { // Should we swallow any further processing of keystroke events for this keydown-keypress sequence? if(LeventMatched) { - let transcription = outputTarget.buildTranscriptionFrom(preInputMock, keyEvent); + let alternates: Alternate[]; + + if(keyEvent.keyDistribution) { + let activeLayout = keyman['osk'].vkbd.layout as osk.ActiveLayout; + alternates = []; + + for(let pair of keyEvent.keyDistribution) { + let mock = Mock.from(preInputMock); + + let altKey = activeLayout.getLayer(keyEvent.kbdLayer).getKey(pair.keyId); + if(!altKey) { + console.warn("Potential fat-finger key could not be found in layer!"); + continue; + } + let altEvent = this._GetClickEventProperties(altKey, keyEvent.Ltarg); + if(this.processKeystroke(altEvent, mock, fromOSK, true)) { + alternates.push({t: mock.buildTransformFrom(preInputMock), 'p': pair.p}); + } + } + } + + let transcription = outputTarget.buildTranscriptionFrom(preInputMock, keyEvent, alternates); // Notify the ModelManager of new input keyman.modelManager.predict(transcription); @@ -535,7 +556,7 @@ namespace com.keyman.text { mappingEvent.kName = 'K_xxxx'; mappingEvent.Ltarg = null; - var mappedChar: string = this.defaultKeyOutput(Lkc, (shifted ? 0x10 : 0), false); + var mappedChar: string = this.defaultKeyOutput(Lkc, (shifted ? 0x10 : 0), false, true); if(mappedChar) { // FIXME; Warning - will return 96 for 'a', which is a keycode corresponding to Codes.keyCodes('K_NP1') - a numpad key. Lkc.Lcode = mappedChar.charCodeAt(0); diff --git a/web/unit_tests/cases/transcriptions.js b/web/unit_tests/cases/transcriptions.js index 6558cb309c..3c5cb3662e 100644 --- a/web/unit_tests/cases/transcriptions.js +++ b/web/unit_tests/cases/transcriptions.js @@ -150,7 +150,7 @@ describe("Transcriptions and Transforms", function() { }); }); - describe("Operations with deadkeys", function() { + /*describe("Operations with deadkeys", function() { // Just one, less nuanced/subdivided; it's not a present priority for our work, but it should provide a decent basis if/when it's needed. it("Correctly recognizes deadkey set mutations", function() { var Mock = com.keyman.text.Mock; @@ -193,4 +193,5 @@ describe("Transcriptions and Transforms", function() { assert.deepEqual({d: ins[0].d, p: ins[0].p}, {d: 3, p:2}, "Selected wrong deadkey as inserted"); }); }); + */ }); \ No newline at end of file