No "+formFactor+" layout is defined for "+PKbd.name+".
"; } // Add a faint border kbd.style.border='1px solid #ccc'; return kbd; } onHide() { // Remove highlighting from hide keyboard key, if applied if(this.hkKey) { this.highlightKey(this.hkKey,false); } } /** * Starts an implementation-specific longpress gesture. Separately implemented for * in-browser and embedded modes. * @param key The base key of the longpress. * @returns */ startLongpress(key: KeyElement): PendingGesture { let _this = this; // First-level object/Promise: will produce a subkey popup when the longpress gesture completes. // 'Returns' a second-level object/Promise: resolves when a subkey is selected or is cancelled. let pendingLongpress = new browser.PendingLongpress(this, key); pendingLongpress.promise.then(function(subkeyPopup) { // In-browser-specific handling. if(subkeyPopup) { // Append the touch-hold (subkey) array to the OSK let keyman = com.keyman.singleton; keyman.osk._Box.appendChild(subkeyPopup.element); keyman.osk._Box.appendChild(subkeyPopup.shim); // Must be placed after its `.element` has been inserted into the DOM. subkeyPopup.reposition(_this); } }); return pendingLongpress; } /** * 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, touch: Touch) { if(key['subKeys']) { let _this = this; let pendingLongpress = this.startLongpress(key); if(pendingLongpress == null) { return; } this.pendingSubkey = pendingLongpress; pendingLongpress.promise.then(function(subkeyPopup) { if(_this.pendingSubkey == pendingLongpress) { _this.pendingSubkey = null; } if(subkeyPopup) { // Clear key preview if any _this.showKeyTip(null,false); _this.subkeyGesture = subkeyPopup; subkeyPopup.promise.then(function(keyEvent: text.KeyEvent) { // Allow active cancellation, even if the source should allow passive. // It's an easy and cheap null guard. if(keyEvent) { PreProcessor.raiseKeyEvent(keyEvent); } _this.clearPopup(); }); } }); } } /** * 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 touch The current touch-coordinate for the gesture * @returns true if should fully capture input, false if input should 'fall through'. */ updateGestures(currentKey: KeyElement, previousKey: KeyElement, touch: Touch): boolean { let key0 = previousKey; let key1 = currentKey; // Clear previous key highlighting, allow subkey controller to highlight as appropriate. if(this.subkeyGesture) { if(key0) { key0.key.highlight(false); } this.subkeyGesture.updateTouch(touch); this.keyPending = null; this.touchPending = null; return true; } this.currentTarget = null; // If popup is visible, need to move over popup, not over main keyboard // Could be turned into a browser-longpress specific implementation within browser.PendingLongpress? if(key1 && key1['subKeys'] != null) { // Show popup keys immediately if touch moved up towards key array (KMEW-100, Build 353) if((this.touchY - touch.pageY > 5) && this.pendingSubkey && this.pendingSubkey instanceof browser.PendingLongpress) { this.pendingSubkey.resolve(); } } // 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) { return true; } if(key0 && key1 && (key1 != key0) && (key1.id != '')) { // While there may not be an active subkey menu, we should probably update which base key // is being highlighted by the current touch & start a pending longpress for it. this.clearPopup(); this.initGestures(key1, touch); } return false; } optionKey(e: KeyElement, keyName: string, keyDown: boolean) { let keyman = com.keyman.singleton; let oskManager = keyman.osk; if(keyDown) { if(keyName.indexOf('K_LOPT') >= 0) { oskManager.showLanguageMenu(); } else if(keyName.indexOf('K_ROPT') >= 0) { keyman.uiManager.setActivatingUI(false); oskManager._Hide(true); let active = keyman.domManager.getActiveElement(); if(dom.Utils.instanceof(active, "TouchAliasElement")) { (active as dom.TouchAliasElement).hideCaret(); } keyman.domManager.clearLastActiveElement(); } } }; /** * Add (or remove) the keytip preview (if KeymanWeb on a phone device) * * @param {Object} key HTML key element * @param {boolean} on show or hide */ showKeyTip(key: KeyElement, on: boolean) { var tip=this.keytip; // Do not change the key preview unless key or state has changed if(tip == null || (key == tip.key && on == tip.state)) { return; } let sk = this.subkeyGesture; let popup = (sk && sk.isVisible()); // If popup keys are active, do not show the key tip. on = popup ? false : on; tip.show(key, on, this); }; /** * Create a key preview element for phone devices */ createKeyTip() { let keyman = com.keyman.singleton; if(this.device.formFactor == 'phone') { if(this.keytip == null) { // For now, should only be true (in production) when keyman.isEmbedded == true. let constrainPopup = keyman.isEmbedded; this.keytip = new browser.KeyTip(constrainPopup); } // Always append to _Box (since cleared during OSK Load) if(this.keytip && this.keytip.element) { keyman.osk._Box.appendChild(this.keytip.element); } } }; /** * Wait until font is loaded before applying stylesheet - test each 100 ms * @param {Object} kfd main font descriptor * @param {Object} ofd secondary font descriptor (OSK only) * @return {boolean} */ waitForFonts(kfd, ofd) { let keymanweb = com.keyman.singleton; let util = keymanweb.util; let fontDefined = !!(kfd && kfd['files']); kfd = fontDefined ? kfd : undefined; let oskFontDefined = !!(ofd && ofd['files']); ofd = oskFontDefined ? ofd : undefined; // Automatically 'ready' if the descriptor is explicitly `undefined`. // Thus, also covers the case where both are undefined. var kReady=util.checkFontDescriptor(kfd), oReady=util.checkFontDescriptor(ofd); if(kReady && oReady) { return true; } keymanweb.fontCheckTimer=window.setInterval(function() { if(util.checkFontDescriptor(kfd) && util.checkFontDescriptor(ofd)) { window.clearInterval(keymanweb.fontCheckTimer); keymanweb.fontCheckTimer=null; keymanweb.alignInputs(); } }, 100); // Align anyway as best as can if font appears to remain uninstalled after 5 seconds window.setTimeout(function() { if(keymanweb.fontCheckTimer) { window.clearInterval(keymanweb.fontCheckTimer); keymanweb.fontCheckTimer=null; keymanweb.alignInputs(); // Don't notify - this is a management issue, not anything the user needs to deal with // TODO: Consider having an icon in the OSK with a bubble that indicates missing font //util.alert('Unable to download the font normally used with '+ks['KN']+'.'); } }, 5000); return false; }; shutdown() { let keyman = com.keyman.singleton; // Prevents style-sheet pollution from multiple keyboard swaps. if(this.styleSheet) { keyman.util.removeStyleSheet(this.styleSheet); } } } }