mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-26 01:27:42 +00:00
feat(web): basic support for newContext
Relates to #3621. Adds basic support for `begin newContext`.
This commit is contained in:
parent
80db98a5f9
commit
bbbf1afce7
10 changed files with 467 additions and 335 deletions
|
|
@ -10,14 +10,16 @@ namespace com.keyman.text {
|
|||
baseLayout: 'us'
|
||||
}
|
||||
|
||||
private device: utils.DeviceSpec;
|
||||
private kbdProcessor: KeyboardProcessor;
|
||||
private lngProcessor: prediction.LanguageProcessor;
|
||||
|
||||
constructor(options?: ProcessorInitOptions) {
|
||||
constructor(device: utils.DeviceSpec, options?: ProcessorInitOptions) {
|
||||
if(!options) {
|
||||
options = InputProcessor.DEFAULT_OPTIONS;
|
||||
}
|
||||
|
||||
this.device = device;
|
||||
this.kbdProcessor = new KeyboardProcessor(options);
|
||||
this.lngProcessor = new prediction.LanguageProcessor();
|
||||
}
|
||||
|
|
@ -50,11 +52,28 @@ namespace com.keyman.text {
|
|||
return this.languageProcessor.activeModel;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
*
|
||||
* @param outputTarget
|
||||
* @returns
|
||||
*/
|
||||
processNewContextEvent(outputTarget: OutputTarget): RuleBehavior {
|
||||
// We presently need the true keystroke to run on the FULL context. That index is still
|
||||
// needed for some indexing operations when comparing two different output targets.
|
||||
const ruleBehavior = this.keyboardProcessor.processNewContextEvent(this.device, outputTarget);
|
||||
|
||||
// Should we swallow any further processing of keystroke events for this?
|
||||
if(ruleBehavior != null) {
|
||||
ruleBehavior.finalize(this.keyboardProcessor, outputTarget);
|
||||
}
|
||||
return ruleBehavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a keystroke according to the touched keyboard button element
|
||||
*
|
||||
* Handles default output and keyboard processing for both OSK and physical keystrokes.
|
||||
*
|
||||
*
|
||||
* @param {Object} keyEvent The abstracted KeyEvent to use for keystroke processing
|
||||
* @param {Object} outputTarget The OutputTarget receiving the KeyEvent
|
||||
* @returns {Object} A RuleBehavior object describing the cumulative effects of
|
||||
|
|
@ -113,7 +132,7 @@ namespace com.keyman.text {
|
|||
if(keyEvent.kNextLayer) {
|
||||
this.keyboardProcessor.selectLayer(keyEvent);
|
||||
}
|
||||
|
||||
|
||||
// Should we swallow any further processing of keystroke events for this keydown-keypress sequence?
|
||||
if(ruleBehavior != null) {
|
||||
let alternates: Alternate[];
|
||||
|
|
@ -123,7 +142,7 @@ namespace com.keyman.text {
|
|||
if(this.languageProcessor.isActive && !ruleBehavior.triggersDefaultCommand) {
|
||||
let keyDistribution = keyEvent.keyDistribution;
|
||||
|
||||
// We don't need to track absolute indexing during alternate-generation;
|
||||
// We don't need to track absolute indexing during alternate-generation;
|
||||
// only position-relative, so it's better to use a sliding window for context
|
||||
// when making alternates. (Slightly worse for short text, matters greatly
|
||||
// for long text.)
|
||||
|
|
@ -141,7 +160,7 @@ namespace com.keyman.text {
|
|||
let _globalThis = com.keyman.utils.getGlobalObject();
|
||||
let timer: () => number;
|
||||
|
||||
// Available by default on `window` in browsers, but _not_ on `global` in Node,
|
||||
// Available by default on `window` in browsers, but _not_ on `global` in Node,
|
||||
// surprisingly. Since we can't use code dependent on `require` statements
|
||||
// at present, we have to condition upon it actually existing.
|
||||
if(_globalThis['performance'] && _globalThis['performance']['now']) {
|
||||
|
|
@ -152,15 +171,15 @@ namespace com.keyman.text {
|
|||
TIMEOUT_THRESHOLD = timer() + 16; // + 16ms.
|
||||
} // else {
|
||||
// We _could_ just use Date.now() as a backup... but that (probably) only matters
|
||||
// when unit testing. So... we actually don't _need_ time thresholding when in
|
||||
// when unit testing. So... we actually don't _need_ time thresholding when in
|
||||
// a Node environment.
|
||||
// }
|
||||
|
||||
// Tracks a minimum probability for keystroke probability. Anything less will not be
|
||||
// included in alternate calculations.
|
||||
// included in alternate calculations.
|
||||
//
|
||||
// Seek to match SearchSpace.EDIT_DISTANCE_COST_SCALE from the predictive-text engine.
|
||||
// Reasoning for the selected value may be seen there. Short version - keystrokes
|
||||
// Reasoning for the selected value may be seen there. Short version - keystrokes
|
||||
// that _appear_ very precise may otherwise not even consider directly-neighboring keys.
|
||||
let KEYSTROKE_EPSILON = Math.exp(-5);
|
||||
|
||||
|
|
@ -169,7 +188,7 @@ namespace com.keyman.text {
|
|||
|
||||
let activeLayout = this.activeKeyboard.layout(keyEvent.device.formFactor);
|
||||
alternates = [];
|
||||
|
||||
|
||||
let totalMass = 0; // Tracks sum of non-error probabilities.
|
||||
for(let pair of keyDistribution) {
|
||||
if(pair.p < KEYSTROKE_EPSILON) {
|
||||
|
|
@ -184,7 +203,7 @@ namespace com.keyman.text {
|
|||
}
|
||||
|
||||
let mock = Mock.from(windowedMock);
|
||||
|
||||
|
||||
let altKey = activeLayout.getLayer(keyEvent.kbdLayer).getKey(pair.keyId);
|
||||
if(!altKey) {
|
||||
console.warn("Potential fat-finger key could not be found in layer!");
|
||||
|
|
@ -193,14 +212,14 @@ namespace com.keyman.text {
|
|||
|
||||
let altEvent = altKey.constructKeyEvent(this.keyboardProcessor, keyEvent.device);
|
||||
let alternateBehavior = this.keyboardProcessor.processKeystroke(altEvent, mock);
|
||||
|
||||
|
||||
// If alternateBehavior.beep == true, ignore it. It's a disallowed key sequence,
|
||||
// so we expect users to never intend their use.
|
||||
//
|
||||
// Also possible that this set of conditions fail for all evaluated alternates.
|
||||
if(alternateBehavior && !alternateBehavior.beep && pair.p > 0) {
|
||||
let transform: Transform = alternateBehavior.transcription.transform;
|
||||
|
||||
|
||||
// Ensure that the alternate's token id matches that of the current keystroke, as we only
|
||||
// record the matched rule's context (since they match)
|
||||
transform.id = ruleBehavior.transcription.token;
|
||||
|
|
@ -224,7 +243,7 @@ namespace com.keyman.text {
|
|||
ruleBehavior.finalize(this.keyboardProcessor, outputTarget);
|
||||
|
||||
// -- All keystroke (and 'alternate') processing is now complete. Time to finalize everything! --
|
||||
|
||||
|
||||
// Notify the ModelManager of new input - it's predictive text time!
|
||||
if(alternates && alternates.length > 0) {
|
||||
ruleBehavior.transcription.alternates = alternates;
|
||||
|
|
@ -245,6 +264,12 @@ namespace com.keyman.text {
|
|||
public resetContext(outputTarget?: OutputTarget) {
|
||||
this.keyboardProcessor.resetContext();
|
||||
this.languageProcessor.invalidateContext(outputTarget);
|
||||
|
||||
// Let the keyboard do its initial group processing
|
||||
//console.log('processNewContextEvent called from resetContext');
|
||||
if(outputTarget) {
|
||||
this.processNewContextEvent(outputTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ namespace com.keyman.keyboards {
|
|||
return this.scriptObject['gs'](outputTarget, keystroke);
|
||||
}
|
||||
|
||||
processNewContextEvent(outputTarget: text.OutputTarget, keystroke: text.KeyEvent): boolean {
|
||||
return this.scriptObject['gn'] ? this.scriptObject['gn'](outputTarget, keystroke) : false;
|
||||
}
|
||||
|
||||
get isHollow(): boolean {
|
||||
return this.scriptObject == Keyboard.DEFAULT_SCRIPT_OBJECT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -948,6 +948,60 @@ namespace com.keyman.text {
|
|||
this.output(1, outputTarget, "");
|
||||
}
|
||||
|
||||
processNewContextEvent(outputTarget: OutputTarget, keystroke: KeyEvent): RuleBehavior {
|
||||
// Clear internal state tracking data from prior keystrokes.
|
||||
if(!outputTarget) {
|
||||
throw "No target specified for keyboard output!";
|
||||
} else if(!this.activeKeyboard) {
|
||||
throw "No active keyboard for keystroke processing!";
|
||||
}
|
||||
|
||||
outputTarget.invalidateSelection();
|
||||
|
||||
outputTarget.deadkeys().resetMatched(); // I3318
|
||||
this.resetContextCache();
|
||||
|
||||
// Capture the initial state of the OutputTarget before any rules are matched.
|
||||
let preInput = Mock.from(outputTarget);
|
||||
|
||||
// Capture the initial state of any variable stores
|
||||
const cachedVariableStores = this.activeKeyboard.variableStores;
|
||||
|
||||
// Establishes the results object, allowing corresponding commands to set values here as appropriate.
|
||||
this.ruleBehavior = new RuleBehavior();
|
||||
|
||||
// Ensure the settings are in place so that KIFS/ifState activates and deactivates
|
||||
// the appropriate rule(s) for the modeled device.
|
||||
this.activeDevice = keystroke.device;
|
||||
|
||||
// Calls the start-group of the active keyboard.
|
||||
this.activeTargetOutput = outputTarget;
|
||||
var matched = this.activeKeyboard.processNewContextEvent(outputTarget, keystroke);
|
||||
this.activeTargetOutput = null;
|
||||
|
||||
// Finalize the rule's results.
|
||||
this.ruleBehavior.transcription = outputTarget.buildTranscriptionFrom(preInput, keystroke);
|
||||
|
||||
// We always backup the changes to variable stores to the RuleBehavior, to
|
||||
// be applied during finalization, then restore them to the cached initial
|
||||
// values to avoid side-effects with predictive text mocks.
|
||||
this.ruleBehavior.variableStores = this.activeKeyboard.variableStores;
|
||||
this.activeKeyboard.variableStores = cachedVariableStores;
|
||||
|
||||
// `matched` refers to whether or not the FINAL rule (from any group) matched, rather than
|
||||
// whether or not ANY rule matched. If the final rule doesn't match, we trigger the key's
|
||||
// default behavior (if appropriate).
|
||||
//
|
||||
// See https://github.com/keymanapp/keyman/pull/4350#issuecomment-768753852
|
||||
this.ruleBehavior.triggerKeyDefault = !matched;
|
||||
|
||||
// Clear our result-tracking variable to prevent any possible pollution for future processing.
|
||||
let behavior = this.ruleBehavior;
|
||||
this.ruleBehavior = null;
|
||||
|
||||
return behavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function processKeystroke
|
||||
* Scope Private
|
||||
|
|
|
|||
|
|
@ -207,6 +207,19 @@ namespace com.keyman.text {
|
|||
}
|
||||
}
|
||||
|
||||
processNewContextEvent(device: utils.DeviceSpec, outputTarget: OutputTarget): RuleBehavior {
|
||||
// Pass this key code and state to the keyboard program
|
||||
if(!this.activeKeyboard) {
|
||||
return null;
|
||||
}
|
||||
let keyEvent = new KeyEvent();
|
||||
keyEvent.Lcode = 0;
|
||||
keyEvent.kName = '';
|
||||
keyEvent.device = device;
|
||||
this.setSyntheticEventDefaults(keyEvent);
|
||||
return this.keyboardInterface.processNewContextEvent(outputTarget, keyEvent);
|
||||
}
|
||||
|
||||
processKeystroke(keyEvent: KeyEvent, outputTarget: OutputTarget): RuleBehavior {
|
||||
var matchBehavior: RuleBehavior;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@
|
|||
|
||||
namespace com.keyman.dom {
|
||||
/*
|
||||
* Note that for many of the actual events represented by methods in this file, `this` is replaced
|
||||
* Note that for many of the actual events represented by methods in this file, `this` is replaced
|
||||
* automatically by JavaScript's event handling system. As such, many 'wrapper' variants of the events
|
||||
* exist to restore the object-oriented hierarchy below.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
export class CommonDOMStates {
|
||||
_DisableInput: boolean = false; // Should input be disabled?
|
||||
_IgnoreNextSelChange: number = 0; // when a visual keyboard key is mouse-down, ignore the next sel change because this stuffs up our history
|
||||
_IgnoreNextSelChange: number = 0; // when a visual keyboard key is mouse-down, ignore the next sel change because this stuffs up our history
|
||||
_IgnoreBlurFocus: boolean = false; // Used to temporarily ignore focus changes
|
||||
_Selection = null;
|
||||
_SelectionControl: any = null; // Type behavior is as with activeElement and the like.
|
||||
|
||||
|
||||
_activeElement: HTMLElement;
|
||||
_lastActiveElement: HTMLElement;
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ namespace com.keyman.dom {
|
|||
// TODO: resolve/refactor out!
|
||||
protected keyman: KeymanBase;
|
||||
|
||||
// This is only static within a given initialization of KeymanWeb. Perhaps it would be best as an initialization
|
||||
// This is only static within a given initialization of KeymanWeb. Perhaps it would be best as an initialization
|
||||
// parameter and member field?
|
||||
static states: CommonDOMStates = new CommonDOMStates();
|
||||
|
||||
|
|
@ -53,12 +53,12 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Handle receiving focus by simulated input field
|
||||
*/
|
||||
*/
|
||||
setFocus: (e?: TouchEvent|MSPointerEvent) => void = function(e?: TouchEvent|MSPointerEvent): void {
|
||||
// Touch-only handler.
|
||||
}.bind(this);
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Handles touch-based loss of focus events.
|
||||
*/
|
||||
setBlur: (e: FocusEvent) => void = function(e: FocusEvent) {
|
||||
|
|
@ -71,8 +71,8 @@ namespace com.keyman.dom {
|
|||
|
||||
//TODO: add more complete description of what ControlFocus really does
|
||||
/**
|
||||
* Respond to KeymanWeb-aware input element receiving focus
|
||||
*/
|
||||
* Respond to KeymanWeb-aware input element receiving focus
|
||||
*/
|
||||
_ControlFocus: (e: FocusEvent) => boolean = function(this: DOMEventHandlers, e: FocusEvent): boolean {
|
||||
var Ltarg: HTMLElement;
|
||||
var device = this.keyman.util.device;
|
||||
|
|
@ -87,7 +87,7 @@ namespace com.keyman.dom {
|
|||
if(Ltarg['body']) {
|
||||
Ltarg = Ltarg['body']; // Occurs in Firefox for design-mode iframes.
|
||||
}
|
||||
|
||||
|
||||
// Prevent any action if a protected input field
|
||||
if(device.touchable && (Ltarg.className == null || Ltarg.className.indexOf('keymanweb-input') < 0)) {
|
||||
return true;
|
||||
|
|
@ -102,7 +102,7 @@ namespace com.keyman.dom {
|
|||
}
|
||||
} else if(Ltarg.ownerDocument && Ltarg.ownerDocument.designMode == 'on') {
|
||||
// continue; don't block this one!
|
||||
} else if((device.touchable || !Ltarg.isContentEditable)
|
||||
} else if((device.touchable || !Ltarg.isContentEditable)
|
||||
&& !(Ltarg.ownerDocument && Ltarg instanceof Ltarg.ownerDocument.defaultView.HTMLTextAreaElement)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ namespace com.keyman.dom {
|
|||
if (Ltarg.nodeType == 3) { // defeat Safari bug
|
||||
Ltarg = Ltarg.parentNode as HTMLElement;
|
||||
}
|
||||
|
||||
|
||||
var LfocusTarg = Ltarg;
|
||||
|
||||
// Ensure that focussed element is visible above the keyboard
|
||||
|
|
@ -122,7 +122,7 @@ namespace com.keyman.dom {
|
|||
(this as DOMTouchHandlers).scrollBody(Ltarg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(Ltarg.ownerDocument && Ltarg instanceof Ltarg.ownerDocument.defaultView.HTMLIFrameElement) { //**TODO: check case reference
|
||||
this.keyman.domManager._AttachToIframe(Ltarg as HTMLIFrameElement);
|
||||
Ltarg=Ltarg.contentWindow.document.body;
|
||||
|
|
@ -131,8 +131,8 @@ namespace com.keyman.dom {
|
|||
// Must set before _Blur / _Focus to avoid infinite recursion due to complications
|
||||
// in setActiveKeyboard behavior with managed keyboard settings.
|
||||
this.keyman.domManager.lastActiveElement = Ltarg;
|
||||
this.keyman.domManager.activeElement = Ltarg; // I3363 (Build 301)
|
||||
|
||||
this.keyman.domManager.activeElement = Ltarg; // I3363 (Build 301)
|
||||
|
||||
if(this.keyman.uiManager.justActivated) {
|
||||
this._BlurKeyboardSettings(Ltarg);
|
||||
} else {
|
||||
|
|
@ -160,9 +160,9 @@ namespace com.keyman.dom {
|
|||
* Scope Private
|
||||
* @param {Object} _target element gaining focus
|
||||
* @param {Object} _activeControl currently active control
|
||||
* @return {boolean}
|
||||
* @return {boolean}
|
||||
* Description Execute external (UI) code needed on focus
|
||||
*/
|
||||
*/
|
||||
doControlFocused(_target: HTMLElement, _activeControl: HTMLElement): boolean {
|
||||
var p={};
|
||||
p['target']=_target;
|
||||
|
|
@ -173,9 +173,9 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Respond to KMW losing focus on event
|
||||
*/
|
||||
*/
|
||||
_ControlBlur: (e: FocusEvent) => boolean = function(this: DOMEventHandlers, e: FocusEvent): boolean {
|
||||
var Ltarg: HTMLElement;
|
||||
var Ltarg: HTMLElement;
|
||||
|
||||
e = this.keyman._GetEventObject<FocusEvent>(e); // I2404 - Manage IE events in IFRAMEs
|
||||
Ltarg = this.keyman.util.eventTarget(e) as HTMLElement;
|
||||
|
|
@ -187,7 +187,7 @@ namespace com.keyman.dom {
|
|||
Ltarg = Ltarg['body']; // Occurs in Firefox for design-mode iframes.
|
||||
}
|
||||
|
||||
// Makes sure we properly detect the TouchAliasElement root,
|
||||
// Makes sure we properly detect the TouchAliasElement root,
|
||||
// rather than one of its constituent children.
|
||||
if(this.keyman.util.device.touchable) {
|
||||
Ltarg = findTouchAliasTarget(Ltarg);
|
||||
|
|
@ -209,7 +209,7 @@ namespace com.keyman.dom {
|
|||
let lastAlias = <TouchAliasElement> this.keyman.domManager.activeElement;
|
||||
lastAlias.hideCaret();
|
||||
}
|
||||
|
||||
|
||||
if (Ltarg.nodeType == 3) { // defeat Safari bug
|
||||
Ltarg = Ltarg.parentNode as HTMLElement;
|
||||
}
|
||||
|
|
@ -219,7 +219,7 @@ namespace com.keyman.dom {
|
|||
Ltarg=Ltarg.contentWindow.frameElement as HTMLElement;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////keymanweb._SelectionControl = null;
|
||||
if(this.keyman.domManager.lastActiveElement) {
|
||||
this._BlurKeyboardSettings(this.keyman.domManager.lastActiveElement);
|
||||
|
|
@ -233,7 +233,7 @@ namespace com.keyman.dom {
|
|||
* the user is manually specifying languages on a per-control basis.
|
||||
*/
|
||||
this.keyman.uiManager.justActivated = false;
|
||||
|
||||
|
||||
var isActivating = this.keyman.uiManager.isActivating;
|
||||
let activeKeyboard = com.keyman.singleton.core.activeKeyboard;
|
||||
if(!isActivating && activeKeyboard) {
|
||||
|
|
@ -255,9 +255,9 @@ namespace com.keyman.dom {
|
|||
* @param {Object} _target element losing focus
|
||||
* @param {Event} _event event object
|
||||
* @param {(boolean|number)} _isActivating activation state
|
||||
* @return {boolean}
|
||||
* @return {boolean}
|
||||
* Description Execute external (UI) code needed on blur
|
||||
*/
|
||||
*/
|
||||
doControlBlurred(_target: HTMLElement, _event: Event, _isActivating: boolean|number): boolean {
|
||||
var p={};
|
||||
p['target']=_target;
|
||||
|
|
@ -275,7 +275,7 @@ namespace com.keyman.dom {
|
|||
_BlurKeyboardSettings(lastElem: HTMLElement, PInternalName?: string, PLgCode?: string) {
|
||||
var keyboardID = this.keyman.core.activeKeyboard ? this.keyman.core.activeKeyboard.id : '';
|
||||
var langCode = this.keyman.keyboardManager.getActiveLanguage();
|
||||
|
||||
|
||||
if(PInternalName !== undefined && PLgCode !== undefined) {
|
||||
keyboardID = PInternalName;
|
||||
langCode = PLgCode;
|
||||
|
|
@ -296,7 +296,7 @@ namespace com.keyman.dom {
|
|||
* Description Restores the newly active element's keyboard settings. Should be called
|
||||
* whenever a KMW-enabled page element gains control, but only once the prior
|
||||
* element's loss of control is guaranteed.
|
||||
*/
|
||||
*/
|
||||
_FocusKeyboardSettings(lastElem: HTMLElement, blockGlobalChange: boolean) {
|
||||
if(lastElem && lastElem._kmwAttachment.keyboard != null) {
|
||||
this.keyman.keyboardManager.setActiveKeyboard(lastElem._kmwAttachment.keyboard,
|
||||
|
|
@ -314,10 +314,10 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Function _CommonFocusHelper
|
||||
* @param {Element} target
|
||||
* @param {Element} target
|
||||
* @returns {boolean}
|
||||
* Description Performs common state management for the various focus events of KeymanWeb.
|
||||
* The return value indicates whether (true) or not (false) the calling event handler
|
||||
* Description Performs common state management for the various focus events of KeymanWeb.
|
||||
* The return value indicates whether (true) or not (false) the calling event handler
|
||||
* should be terminated immediately after the call.
|
||||
*/
|
||||
_CommonFocusHelper(target: HTMLElement): boolean {
|
||||
|
|
@ -328,23 +328,25 @@ namespace com.keyman.dom {
|
|||
if(target.ownerDocument && target instanceof target.ownerDocument.defaultView.HTMLIFrameElement) {
|
||||
if(!this.keyman.domManager._IsIEEditableIframe(target, 1) ||
|
||||
!this.keyman.domManager._IsMozillaEditableIframe(target, 1)) {
|
||||
DOMEventHandlers.states._DisableInput = true;
|
||||
DOMEventHandlers.states._DisableInput = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DOMEventHandlers.states._DisableInput = false;
|
||||
DOMEventHandlers.states._DisableInput = false;
|
||||
|
||||
const outputTarget = dom.Utils.getOutputTarget(target);
|
||||
|
||||
let activeKeyboard = keyman.core.activeKeyboard;
|
||||
if(!uiManager.justActivated) {
|
||||
if(target && Utils.getOutputTarget(target)) {
|
||||
Utils.getOutputTarget(target).deadkeys().clear();
|
||||
if(target && outputTarget) {
|
||||
outputTarget.deadkeys().clear();
|
||||
}
|
||||
|
||||
|
||||
if(activeKeyboard) {
|
||||
activeKeyboard.notify(0, Utils.getOutputTarget(target), 1); // I2187
|
||||
activeKeyboard.notify(0, outputTarget, 1); // I2187
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!uiManager.justActivated && DOMEventHandlers.states._SelectionControl != target) {
|
||||
uiManager.isActivating = false;
|
||||
}
|
||||
|
|
@ -352,8 +354,20 @@ namespace com.keyman.dom {
|
|||
|
||||
DOMEventHandlers.states._SelectionControl = target;
|
||||
|
||||
if(target && outputTarget) {
|
||||
//
|
||||
// Call the current keyboard's newContext handler;
|
||||
// timeout is required in order to get the current
|
||||
// selection, swhich is not ready at time of focus event
|
||||
//
|
||||
window.setTimeout(() => {
|
||||
//console.log('processNewContextEvent called from focus');
|
||||
com.keyman.singleton.core.processNewContextEvent(outputTarget);
|
||||
});
|
||||
}
|
||||
|
||||
if(keyman.core.languageProcessor.isActive) {
|
||||
keyman.core.languageProcessor.predictFromTarget(Utils.getOutputTarget(target));
|
||||
keyman.core.languageProcessor.predictFromTarget(outputTarget);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -361,12 +375,12 @@ namespace com.keyman.dom {
|
|||
/**
|
||||
* Function _SelectionChange
|
||||
* Scope Private
|
||||
* Description Respond to selection change event
|
||||
* Description Respond to selection change event
|
||||
*/
|
||||
_SelectionChange: () => boolean = function(this: DOMEventHandlers): boolean {
|
||||
if(DOMEventHandlers.states._IgnoreNextSelChange) {
|
||||
DOMEventHandlers.states._IgnoreNextSelChange--;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}.bind(this);
|
||||
|
||||
|
|
@ -374,12 +388,12 @@ namespace com.keyman.dom {
|
|||
/**
|
||||
* Function _KeyDown
|
||||
* Scope Private
|
||||
* Description Processes keydown event and passes data to keyboard.
|
||||
*
|
||||
* Description Processes keydown event and passes data to keyboard.
|
||||
*
|
||||
* Note that the test-case oriented 'recorder' stubs this method to facilitate keystroke
|
||||
* recording for use in test cases. If changing this function, please ensure the recorder is
|
||||
* not affected.
|
||||
*/
|
||||
*/
|
||||
_KeyDown: (e: KeyboardEvent) => boolean = function(this: DOMEventHandlers, e: KeyboardEvent): boolean {
|
||||
var activeKeyboard = this.keyman.core.activeKeyboard;
|
||||
var util = this.keyman.util;
|
||||
|
|
@ -395,7 +409,7 @@ namespace com.keyman.dom {
|
|||
return true;
|
||||
}
|
||||
} else if(el && el.className.indexOf('kmw-disabled') >= 0) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return PreProcessor.keyDown(e);
|
||||
|
|
@ -421,11 +435,23 @@ namespace com.keyman.dom {
|
|||
DOMEventHandlers.states.changed = false;
|
||||
}
|
||||
|
||||
_Click: (e: MouseEvent) => boolean = function(this: DOMEventHandlers, e: MouseEvent): boolean {
|
||||
let target = e.target as HTMLElement;
|
||||
if(target && target['base']) {
|
||||
target = target['base'];
|
||||
}
|
||||
|
||||
//console.log('processNewContextEvent called from click');
|
||||
com.keyman.singleton.core.processNewContextEvent(dom.Utils.getOutputTarget(target));
|
||||
|
||||
return true;
|
||||
}.bind(this);
|
||||
|
||||
/**
|
||||
* Function _KeyPress
|
||||
* Scope Private
|
||||
* Description Processes keypress event (does not pass data to keyboard)
|
||||
*/
|
||||
*/
|
||||
_KeyPress: (e: KeyboardEvent) => boolean = function(this: DOMEventHandlers, e: KeyboardEvent): boolean {
|
||||
if(DOMEventHandlers.states._DisableInput || this.keyman.core.activeKeyboard == null) {
|
||||
return true;
|
||||
|
|
@ -438,7 +464,7 @@ namespace com.keyman.dom {
|
|||
* Function _KeyUp
|
||||
* Scope Private
|
||||
* Description Processes keyup event and passes event data to keyboard
|
||||
*/
|
||||
*/
|
||||
_KeyUp: (e: KeyboardEvent) => boolean = function(this: DOMEventHandlers, e: KeyboardEvent): boolean {
|
||||
var osk = this.keyman.osk;
|
||||
|
||||
|
|
@ -457,7 +483,7 @@ namespace com.keyman.dom {
|
|||
if(outputTarget instanceof inputEle.ownerDocument.defaultView.HTMLTextAreaElement) {
|
||||
ignore = true;
|
||||
}
|
||||
|
||||
|
||||
if(inputEle.base && inputEle.base instanceof inputEle.base.ownerDocument.defaultView.HTMLTextAreaElement) {
|
||||
ignore = true;
|
||||
}
|
||||
|
|
@ -473,8 +499,8 @@ namespace com.keyman.dom {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return PreProcessor.keyUp(e);
|
||||
}.bind(this);
|
||||
}
|
||||
|
|
@ -490,7 +516,7 @@ namespace com.keyman.dom {
|
|||
y: number;
|
||||
};
|
||||
|
||||
|
||||
|
||||
constructor(keyman: KeymanBase) {
|
||||
super(keyman);
|
||||
}
|
||||
|
|
@ -510,7 +536,7 @@ namespace com.keyman.dom {
|
|||
// whether or not individual `Touch`es may be related to this specific event for
|
||||
// an ongoing multitouch scenario.
|
||||
let target = e.target;
|
||||
|
||||
|
||||
// Find the first touch affected by this event that matches the current target.
|
||||
for(let i=0; i < e.changedTouches.length; i++) {
|
||||
if(isValidTouch(e.changedTouches[i], target)) {
|
||||
|
|
@ -524,9 +550,9 @@ namespace com.keyman.dom {
|
|||
}
|
||||
|
||||
/**
|
||||
* Handle receiving focus by simulated input field
|
||||
*
|
||||
*/
|
||||
* Handle receiving focus by simulated input field
|
||||
*
|
||||
*/
|
||||
setFocus: (e?: TouchEvent|MSPointerEvent) => void = function(this: DOMTouchHandlers, e?: TouchEvent|MSPointerEvent): void {
|
||||
DOMEventHandlers.states.setFocusTimer();
|
||||
|
||||
|
|
@ -580,7 +606,7 @@ namespace com.keyman.dom {
|
|||
// Some parts rely upon the scroller element.
|
||||
let scroller = target.firstChild as HTMLElement;
|
||||
|
||||
// Move the caret and refocus if necessary
|
||||
// Move the caret and refocus if necessary
|
||||
if(this.keyman.domManager.activeElement != target) {
|
||||
// Hide the KMW caret
|
||||
let prevTarget = <TouchAliasElement> this.keyman.domManager.activeElement;
|
||||
|
|
@ -600,26 +626,26 @@ namespace com.keyman.dom {
|
|||
// The issue here is that touching a DIV does not actually set the focus for iOS, even when enabled to accept focus (by setting tabIndex=0)
|
||||
// We must explicitly set the focus in order to remove focus from any non-KMW input
|
||||
target.focus(); //Android native browsers may not like this, but it is needed for Chrome, Safari
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Correct element directionality if required
|
||||
this.keyman.domManager._SetTargDir(target);
|
||||
|
||||
this.keyman.domManager._SetTargDir(target);
|
||||
|
||||
// If clicked on DIV on the main element, rather than any part of the text representation,
|
||||
// set caret to end of text
|
||||
if(tTarg && tTarg == target) {
|
||||
var x,cp;
|
||||
x=dom.Utils.getAbsoluteX(scroller.firstChild as HTMLElement);
|
||||
if(target.dir == 'rtl') {
|
||||
x += (scroller.firstChild as HTMLElement).offsetWidth;
|
||||
x=dom.Utils.getAbsoluteX(scroller.firstChild as HTMLElement);
|
||||
if(target.dir == 'rtl') {
|
||||
x += (scroller.firstChild as HTMLElement).offsetWidth;
|
||||
cp=(touchX > x ? 0 : 100000);
|
||||
} else {
|
||||
cp=(touchX<x ? 0 : 100000);
|
||||
}
|
||||
|
||||
|
||||
target.setTextCaret(cp);
|
||||
target.scrollInput();
|
||||
// nextSibling - the scrollbar element.
|
||||
// nextSibling - the scrollbar element.
|
||||
} else if(tTarg != scroller.nextSibling) { // Otherwise, if clicked on text in SPAN, set at touch position
|
||||
var caret,cp,cpMin,cpMax,x,y,dy,yRow,iLoop;
|
||||
caret=scroller.childNodes[1]; //caret span
|
||||
|
|
@ -630,10 +656,10 @@ namespace com.keyman.dom {
|
|||
|
||||
// Vertical scrolling
|
||||
if(target.base instanceof target.base.ownerDocument.defaultView.HTMLTextAreaElement) {
|
||||
yRow=Math.round(target.base.offsetHeight/(target.base as HTMLTextAreaElement).rows);
|
||||
yRow=Math.round(target.base.offsetHeight/(target.base as HTMLTextAreaElement).rows);
|
||||
for(iLoop=0; iLoop<16; iLoop++)
|
||||
{
|
||||
y=dom.Utils.getAbsoluteY(caret)-dy; //top of caret
|
||||
y=dom.Utils.getAbsoluteY(caret)-dy; //top of caret
|
||||
if(y > touchY && cp > cpMin && cp != cpMax) {cpMax=cp; cp=Math.round((cp+cpMin)/2);}
|
||||
else if(y < touchY-yRow && cp < cpMax && cp != cpMin) {cpMin=cp; cp=Math.round((cp+cpMax)/2);}
|
||||
else break;
|
||||
|
|
@ -656,21 +682,21 @@ namespace com.keyman.dom {
|
|||
var snapOrder;
|
||||
if(target.dir == 'rtl') { // I would use arrow functions, but IE doesn't like 'em.
|
||||
snapOrder = function(a, b) {
|
||||
return a < b;
|
||||
return a < b;
|
||||
};
|
||||
} else {
|
||||
snapOrder = function(a, b) {
|
||||
return a > b;
|
||||
snapOrder = function(a, b) {
|
||||
return a > b;
|
||||
};
|
||||
}
|
||||
|
||||
for(iLoop=0; iLoop<16; iLoop++) {
|
||||
x=dom.Utils.getAbsoluteX(caret); //left of caret
|
||||
x=dom.Utils.getAbsoluteX(caret); //left of caret
|
||||
if(snapOrder(x, touchX) && cp > cpMin && cp != cpMax) {
|
||||
cpMax=cp;
|
||||
cpMax=cp;
|
||||
cp=Math.round((cp+cpMin)/2);
|
||||
} else if(!snapOrder(x, touchX) && cp < cpMax && cp != cpMin) {
|
||||
cpMin=cp;
|
||||
cpMin=cp;
|
||||
cp=Math.round((cp+cpMax)/2);
|
||||
} else {
|
||||
break;
|
||||
|
|
@ -691,7 +717,7 @@ namespace com.keyman.dom {
|
|||
* for controls, we have to act here to preserve the outgoing control's keyboard settings.
|
||||
*
|
||||
* If we 'just activated' the KeymanWeb UI, we need to save the new keyboard change as appropriate.
|
||||
*/
|
||||
*/
|
||||
if(this.keyman.domManager.lastActiveElement) {
|
||||
this._BlurKeyboardSettings(this.keyman.domManager.lastActiveElement);
|
||||
}
|
||||
|
|
@ -705,7 +731,7 @@ namespace com.keyman.dom {
|
|||
* If not, we need to activate the control's preferred keyboard.
|
||||
*/
|
||||
this._FocusKeyboardSettings(target, false);
|
||||
|
||||
|
||||
// Always do the common focus stuff, instantly returning if we're in an editable iframe.
|
||||
// This parallels the if-statement in _ControlFocus - it may be needed as this if-statement in the future,
|
||||
// despite its present redundancy.
|
||||
|
|
@ -716,15 +742,15 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Close OSK and remove simulated caret on losing focus
|
||||
*/
|
||||
*/
|
||||
cancelInput(): void {
|
||||
this.keyman.domManager.activeElement = null;
|
||||
this.keyman.domManager.activeElement = null;
|
||||
this.keyman.domManager.lastActiveElement = null;
|
||||
this.keyman.osk.hideNow();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle losing focus from simulated input field
|
||||
* Handle losing focus from simulated input field
|
||||
*/
|
||||
setBlur: (e: FocusEvent) => void = function(this: DOMTouchHandlers, e: FocusEvent) {
|
||||
// This works OK for iOS, but may need something else for other platforms
|
||||
|
|
@ -734,7 +760,7 @@ namespace com.keyman.dom {
|
|||
elem = e.relatedTarget as HTMLElement;
|
||||
}
|
||||
|
||||
this.executeBlur(elem);
|
||||
this.executeBlur(elem);
|
||||
}.bind(this);
|
||||
|
||||
executeBlur(elem: HTMLElement) {
|
||||
|
|
@ -743,7 +769,7 @@ namespace com.keyman.dom {
|
|||
if(elem) {
|
||||
this.doChangeEvent(elem);
|
||||
if(elem.nodeName != 'DIV' || elem.className.indexOf('keymanweb-input') == -1) {
|
||||
this.cancelInput();
|
||||
this.cancelInput();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -756,7 +782,7 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Display and position a scrollbar in the input field if needed
|
||||
*
|
||||
*
|
||||
* @param {Object} e input DIV element (copy of INPUT or TEXTAREA)
|
||||
*/
|
||||
setScrollBar(e: HTMLElement) {
|
||||
|
|
@ -767,21 +793,21 @@ namespace com.keyman.dom {
|
|||
sbs.width=100*(e.offsetWidth/scroller.offsetWidth)+'%';
|
||||
sbs.left=100*(-scroller.offsetLeft/scroller.offsetWidth)+'%';
|
||||
sbs.top='0';
|
||||
sbs.visibility='visible';
|
||||
sbs.visibility='visible';
|
||||
} else if(scroller.offsetHeight > e.offsetHeight || scroller.offsetTop < 0) {
|
||||
sbs.width='4px';
|
||||
sbs.height=100*(e.offsetHeight/scroller.offsetHeight)+'%';
|
||||
sbs.top=100*(-scroller.offsetTop/scroller.offsetHeight)+'%';
|
||||
sbs.left='0';
|
||||
sbs.visibility='visible';
|
||||
sbs.left='0';
|
||||
sbs.visibility='visible';
|
||||
} else {
|
||||
sbs.visibility='hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the touch move event for an input element
|
||||
*/
|
||||
*/
|
||||
dragInput: (e: TouchEvent|MouseEvent) => void = function(this: DOMTouchHandlers, e: TouchEvent|MouseEvent) {
|
||||
// Prevent dragging window
|
||||
if(e.cancelable) {
|
||||
|
|
@ -789,12 +815,12 @@ namespace com.keyman.dom {
|
|||
// Tends to result in a spam of console errors when e.cancelable == false.
|
||||
e.preventDefault();
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.stopPropagation();
|
||||
|
||||
// Identify the target from the touch list or the event argument (IE 10 only)
|
||||
var target: HTMLElement;
|
||||
let touch: Touch;
|
||||
|
||||
|
||||
if(dom.Utils.instanceof(e, "TouchEvent")) {
|
||||
try {
|
||||
touch=DOMTouchHandlers.selectTouch(e as TouchEvent);
|
||||
|
|
@ -809,7 +835,7 @@ namespace com.keyman.dom {
|
|||
if(target == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Identify the input element from the touch event target (touched element may be contained by input)
|
||||
target = findTouchAliasTarget(target);
|
||||
|
||||
|
|
@ -826,22 +852,22 @@ namespace com.keyman.dom {
|
|||
x = (e as MouseEvent).screenX;
|
||||
y = (e as MouseEvent).screenY;
|
||||
}
|
||||
|
||||
|
||||
// Allow content of input elements to be dragged horizontally or vertically
|
||||
if(typeof this.firstTouch == 'undefined' || this.firstTouch == null) {
|
||||
this.firstTouch={x:x,y:y};
|
||||
} else {
|
||||
var x0=this.firstTouch.x,y0=this.firstTouch.y,
|
||||
scroller=target.firstChild as HTMLElement,dx,dy,x1;
|
||||
|
||||
|
||||
if(target.base.nodeName == 'TEXTAREA') {
|
||||
var yOffset=parseInt(scroller.style.top,10);
|
||||
if(isNaN(yOffset)) yOffset=0;
|
||||
dy=y0-y;
|
||||
if(dy < -4 || dy > 4) {
|
||||
scroller.style.top=(yOffset<dy?yOffset-dy:0)+'px';
|
||||
this.firstTouch.y=y;
|
||||
}
|
||||
this.firstTouch.y=y;
|
||||
}
|
||||
} else {
|
||||
var xOffset=parseInt(scroller.style.left,10);
|
||||
if(isNaN(xOffset)) xOffset=0;
|
||||
|
|
@ -850,13 +876,13 @@ namespace com.keyman.dom {
|
|||
{
|
||||
// Limit dragging beyond the defined text (to avoid dragging the text completely out of view)
|
||||
var xMin=0, xMax= dom.Utils.getAbsoluteX(target)+target.offsetWidth-scroller.offsetWidth-32;
|
||||
if(target.base.dir == 'rtl')xMin=16; else xMax=xMax-24;
|
||||
if(target.base.dir == 'rtl')xMin=16; else xMax=xMax-24;
|
||||
x1=xOffset-dx;
|
||||
if(x1 > xMin) x1=xMin;
|
||||
if(x1 < xMax) x1=xMax;
|
||||
scroller.style.left=x1+'px';
|
||||
this.firstTouch.x=x;
|
||||
}
|
||||
this.firstTouch.x=x;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Should refactor to use TouchAliasElement's version; target is an instance of the class.
|
||||
|
|
@ -865,9 +891,9 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Scroll the document body vertically to bring the active input into view
|
||||
*
|
||||
*
|
||||
* @param {Object} e simulated input field object being focussed
|
||||
*/
|
||||
*/
|
||||
scrollBody(e: HTMLElement): void {
|
||||
var osk = this.keyman.osk;
|
||||
|
||||
|
|
@ -882,7 +908,7 @@ namespace com.keyman.dom {
|
|||
} else {
|
||||
dy=y-t-(window.innerHeight-osk._Box.offsetHeight-s2.offsetHeight-2);
|
||||
if(dy < 0) dy=0;
|
||||
}
|
||||
}
|
||||
// Hide OSK, then scroll, then re-anchor OSK with absolute position (on end of scroll event)
|
||||
if(dy != 0) {
|
||||
window.scrollTo(0,dy+window.pageYOffset);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -21,13 +21,13 @@ namespace com.keyman.dom {
|
|||
* Scope Private
|
||||
* @param {Event} e Event object
|
||||
* @param {boolean=} keyState true if call results from a keyDown event, false if keyUp, undefined if keyPress
|
||||
* @return {Object.<string,*>} KMW keyboard event object:
|
||||
* Description Get object with target element, key code, shift state, virtual key state
|
||||
* @return {Object.<string,*>} KMW keyboard event object:
|
||||
* Description Get object with target element, key code, shift state, virtual key state
|
||||
* Lcode=keyCode
|
||||
* Lmodifiers=shiftState
|
||||
* LisVirtualKeyCode e.g. ctrl/alt key
|
||||
* LisVirtualKey e.g. Virtual key or non-keypress event
|
||||
*/
|
||||
*/
|
||||
static _GetKeyEventProperties(e: KeyboardEvent, keyState?: boolean): text.KeyEvent {
|
||||
let keyman = com.keyman.singleton;
|
||||
let core = keyman.core;
|
||||
|
|
@ -46,7 +46,7 @@ namespace com.keyman.dom {
|
|||
// Stage 1 - track the true state of the keyboard's modifiers.
|
||||
var prevModState = core.keyboardProcessor.modStateFlags, curModState = 0x0000;
|
||||
var ctrlEvent = false, altEvent = false;
|
||||
|
||||
|
||||
let keyCodes = text.Codes.keyCodes;
|
||||
switch(s.Lcode) {
|
||||
case keyCodes['K_CTRL']: // The 3 shorter "K_*CTRL" entries exist in some legacy keyboards.
|
||||
|
|
@ -68,16 +68,16 @@ namespace com.keyman.dom {
|
|||
|
||||
/**
|
||||
* Two separate conditions exist that should trigger chiral modifier detection. Examples below use CTRL but also work for ALT.
|
||||
*
|
||||
* 1. The user literally just pressed CTRL, so the event has a valid `location` property we can utilize.
|
||||
*
|
||||
* 1. The user literally just pressed CTRL, so the event has a valid `location` property we can utilize.
|
||||
* Problem: its layer isn't presently activated within the OSK.
|
||||
*
|
||||
*
|
||||
* 2. CTRL has been held a while, so the OSK layer is valid, but the key event doesn't tell us the chirality of the active CTRL press.
|
||||
* Bonus issue: RAlt simulation may cause erasure of this location property, but it should ONLY be empty if pressed in this case.
|
||||
* We default to the 'left' variants since they're more likely to exist and cause less issues with RAlt simulation handling.
|
||||
*
|
||||
*
|
||||
* In either case, `e.getModifierState("Control")` is set to true, but as a result does nothing to tell us which case is active.
|
||||
*
|
||||
*
|
||||
* `e.location != 0` if true matches condition 1 and matches condition 2 if false.
|
||||
*/
|
||||
|
||||
|
|
@ -85,19 +85,19 @@ namespace com.keyman.dom {
|
|||
|
||||
let modifierCodes = text.Codes.modifierCodes;
|
||||
if(e.getModifierState("Control")) {
|
||||
curModState |= ((e.location != 0 && ctrlEvent) ?
|
||||
curModState |= ((e.location != 0 && ctrlEvent) ?
|
||||
(e.location == 1 ? modifierCodes['LCTRL'] : modifierCodes['RCTRL']) : // Condition 1
|
||||
prevModState & 0x0003); // Condition 2
|
||||
}
|
||||
if(e.getModifierState("Alt")) {
|
||||
curModState |= ((e.location != 0 && altEvent) ?
|
||||
curModState |= ((e.location != 0 && altEvent) ?
|
||||
(e.location == 1 ? modifierCodes['LALT'] : modifierCodes['RALT']) : // Condition 1
|
||||
prevModState & 0x000C); // Condition 2
|
||||
}
|
||||
|
||||
// Stage 2 - detect state key information. It can be looked up per keypress with no issue.
|
||||
s.Lstates = 0;
|
||||
|
||||
|
||||
s.Lstates |= e.getModifierState('CapsLock') ? modifierCodes['CAPS'] : modifierCodes['NO_CAPS'];
|
||||
s.Lstates |= e.getModifierState('NumLock') ? modifierCodes['NUM_LOCK'] : modifierCodes['NO_NUM_LOCK'];
|
||||
s.Lstates |= (e.getModifierState('ScrollLock') || e.getModifierState("Scroll")) // "Scroll" for IE9.
|
||||
|
|
@ -134,14 +134,14 @@ namespace com.keyman.dom {
|
|||
}
|
||||
} else {
|
||||
// No need to sim AltGr here; we don't need chiral ALTs.
|
||||
s.Lmodifiers =
|
||||
s.Lmodifiers =
|
||||
(curModState & 0x10) | // SHIFT
|
||||
((curModState & (modifierCodes['LCTRL'] | modifierCodes['RCTRL'])) ? 0x20 : 0) |
|
||||
((curModState & (modifierCodes['LALT'] | modifierCodes['RALT'])) ? 0x40 : 0);
|
||||
((curModState & (modifierCodes['LCTRL'] | modifierCodes['RCTRL'])) ? 0x20 : 0) |
|
||||
((curModState & (modifierCodes['LALT'] | modifierCodes['RALT'])) ? 0x40 : 0);
|
||||
}
|
||||
|
||||
|
||||
/* Tweak the modifiers if an OS meta key is detected; this will allow meta-key-based
|
||||
/* Tweak the modifiers if an OS meta key is detected; this will allow meta-key-based
|
||||
* hotkeys to bypass Keyman processing. We do this AFTER the chiral modifier filtering
|
||||
* because some keyboards specify their own modifierBitmask, which won't include it.
|
||||
* We don't currently use that reference in this method, but that may change in the future.
|
||||
|
|
@ -151,7 +151,7 @@ namespace com.keyman.dom {
|
|||
// Physically-typed keys require use of a 'desktop' form factor and thus are based on a virtual "physical" Device.
|
||||
s.device = keyman.util.physicalDevice.coreSpec;
|
||||
|
||||
// Perform any browser-specific key remapping before other remaps and mnemonic transforms.
|
||||
// Perform any browser-specific key remapping before other remaps and mnemonic transforms.
|
||||
// (See https://github.com/keymanapp/keyman/issues/1125.)
|
||||
if(!keyman.isEmbedded && s.device.browser == utils.Browser.Firefox) {
|
||||
// Browser key identifiers are not completely consistent; Firefox has a few (for US punctuation)
|
||||
|
|
@ -185,7 +185,7 @@ namespace com.keyman.dom {
|
|||
s.Lcode=Lbase['k'+s.Lcode];
|
||||
}
|
||||
/* 13/03/2007 MCD: Swedish: End mapping of keystroke to US keyboard */
|
||||
|
||||
|
||||
if(!activeKeyboard.definesPositionalOrMnemonic && !(s.Lmodifiers & 0x60)) {
|
||||
// Support version 1.0 KeymanWeb keyboards that do not define positional vs mnemonic
|
||||
s = {
|
||||
|
|
@ -200,11 +200,11 @@ namespace com.keyman.dom {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static getEventOutputTarget(e: KeyboardEvent): text.OutputTarget {
|
||||
public static getEventOutputTarget(e: Event): text.OutputTarget {
|
||||
let keyman = com.keyman.singleton;
|
||||
let target = keyman.util.eventTarget(e) as HTMLElement;
|
||||
if (target == null) {
|
||||
|
|
@ -219,17 +219,17 @@ namespace com.keyman.dom {
|
|||
/**
|
||||
* Function keyDown
|
||||
* Scope Public
|
||||
* Description Processes keydown event and passes data to keyboard.
|
||||
*
|
||||
* Description Processes keydown event and passes data to keyboard.
|
||||
*
|
||||
* Note that the test-case oriented 'recorder' stubs this method to facilitate keystroke
|
||||
* recording for use in test cases. If changing this function, please ensure the recorder is
|
||||
* not affected.
|
||||
*/
|
||||
*/
|
||||
static keyDown(e: KeyboardEvent): boolean {
|
||||
let core = com.keyman.singleton.core;
|
||||
DOMEventHandlers.states.swallowKeypress = false;
|
||||
|
||||
// Get event properties
|
||||
// Get event properties
|
||||
var Levent = this._GetKeyEventProperties(e, true);
|
||||
if(Levent == null) {
|
||||
return true;
|
||||
|
|
@ -298,7 +298,7 @@ namespace com.keyman.dom {
|
|||
return false;
|
||||
}
|
||||
/* I732 END - 13/03/2007 MCD: Swedish: End positional keyboard layout code */
|
||||
|
||||
|
||||
// Only reached if it's a mnemonic keyboard.
|
||||
let outputTarget = PreProcessor.getEventOutputTarget(e);
|
||||
if(DOMEventHandlers.states.swallowKeypress || core.keyboardInterface.processKeystroke(outputTarget, Levent)) {
|
||||
|
|
|
|||
|
|
@ -765,6 +765,10 @@ namespace com.keyman.keyboards {
|
|||
if(osk) {
|
||||
osk._Load();
|
||||
}
|
||||
|
||||
if(manager.keymanweb.domManager.lastActiveElement != null) {
|
||||
core.processNewContextEvent(dom.Utils.getOutputTarget(manager.keymanweb.domManager.lastActiveElement));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the wait message, if defined
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ namespace com.keyman {
|
|||
}
|
||||
this._BrowserIsSafari = (navigator.userAgent.indexOf('AppleWebKit') >= 0); // I732 END - Support for European underlying keyboards #1
|
||||
|
||||
this.core = new text.InputProcessor({
|
||||
this.core = new text.InputProcessor(this.util.device.coreSpec, {
|
||||
baseLayout: baseLayout,
|
||||
variableStoreSerializer: new dom.VariableStoreCookieSerializer()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -616,10 +616,10 @@ namespace com.keyman.osk {
|
|||
// This handler is also triggered on state-key state changes (K_CAPS) that
|
||||
// may not actually change the layer.
|
||||
if(this.vkbd) {
|
||||
this.vkbd._UpdateVKShiftStyle();
|
||||
this.vkbd._UpdateVKShiftStyle(newValue);
|
||||
}
|
||||
|
||||
if(source.value != newValue) {
|
||||
if((this.vkbd && this.vkbd.layerId != newValue) || source.value != newValue) {
|
||||
// Prevents console errors when a keyboard only displays help.
|
||||
// Can occur when using SHIFT with sil_euro_latin on a desktop form-factor.
|
||||
if(this.vkbd) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue