Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions common/core/web/input-processor/src/text/inputProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,13 @@ namespace com.keyman.text {
}

// Will handle keystroke-based non-layer change modifier & state keys, mapping them through the physical keyboard's version
// of state management.
if(!fromOSK && this.keyboardProcessor.doModifierPress(keyEvent, !fromOSK)) {
return new RuleBehavior();
// of state management. `doModifierPress` must always run.
if(this.keyboardProcessor.doModifierPress(keyEvent, !fromOSK)) {
// If run on a desktop platform, we know that modifier & state key presses may not
// produce output, so we may make an immediate return safely.
if(!fromOSK) {
return new RuleBehavior();
}
}

// If suggestions exist AND space is pressed, accept the suggestion and do not process the keystroke.
Expand Down
16 changes: 15 additions & 1 deletion common/core/web/keyboard-processor/src/keyboards/activeLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,20 @@ namespace com.keyman.keyboards {
// This part depends on the keyboard processor's active state.
if(keyboardProcessor) {
keyboardProcessor.setSyntheticEventDefaults(Lkc);

// If it's a state key modifier, trigger its effects as part of the
// keystroke.
const bitmap = {
'K_CAPS': text.Codes.stateBitmasks.CAPS,
'K_NUMLOCK': text.Codes.stateBitmasks.NUM_LOCK,
'K_SCROLL': text.Codes.stateBitmasks.SCROLL_LOCK
};
const bitmask = bitmap[Lkc.kName];

if(bitmask) {
Lkc.Lstates ^= bitmask;
Lkc.LmodifierChange = true;
}
}

return Lkc;
Expand Down Expand Up @@ -670,4 +684,4 @@ namespace com.keyman.keyboards {
return aLayout;
}
}
}
}
36 changes: 35 additions & 1 deletion common/core/web/keyboard-processor/src/text/keyboardProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ namespace com.keyman.text {

for(i=0; i < lockNames.length; i++) {
if(lockStates & Codes.stateBitmasks[lockNames[i]]) {
this.stateKeys[lockKeys[i]] = lockStates & Codes.modifierCodes[lockNames[i]];
this.stateKeys[lockKeys[i]] = !!(lockStates & Codes.modifierCodes[lockNames[i]]);
}
}
} else if(d) {
Expand All @@ -427,10 +427,44 @@ namespace com.keyman.text {
}
}

this.updateStates();

if(this.activeKeyboard.isMnemonic && this.stateKeys['K_CAPS']) {
// Modifier keypresses doesn't trigger mnemonic manipulation of modifier state.
// Only an output key does; active use of Caps will also flip the SHIFT flag.
if(!e || !KeyboardProcessor.isModifier(e)) {
// Mnemonic keystrokes manipulate the SHIFT property based on CAPS state.
// We need to unflip them when tracking the OSK layer.
keyShiftState ^= Codes.modifierCodes['SHIFT'];
}
}

this.layerId = this.getLayerId(keyShiftState);
return true;
}

private updateStates(): void {
var lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'];
var lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'];

for(let i=0; i < lockKeys.length; i++) {
const key = lockKeys[i];
const flag = this.stateKeys[key];
const onBit = lockNames[i];
const offBit = 'NO_' + lockNames[i];

// Ensures that the current mod-state info properly matches the currently-simulated
// state key states.
if(flag) {
this.modStateFlags |= Codes.modifierCodes[onBit];
this.modStateFlags &= ~Codes.modifierCodes[offBit];
} else {
this.modStateFlags &= ~Codes.modifierCodes[onBit];
this.modStateFlags |= Codes.modifierCodes[offBit];
}
}
}

getLayerId(modifier: number): string {
return keyboards.Layouts.getLayerId(modifier);
}
Expand Down
8 changes: 0 additions & 8 deletions web/source/osk/preProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@ namespace com.keyman.osk {
// First check the virtual key, and process shift, control, alt or function keys
let Lkc = e.constructKeyEvent(core.keyboardProcessor, dom.Utils.getOutputTarget(Lelem), keyman.util.device.coreSpec);

// If it's actually a state key modifier, trigger its effects immediately, as KeyboardEvents would do the same.
switch(Lkc.kName) {
case 'K_CAPS':
case 'K_NUMLOCK':
case 'K_SCROLL':
core.keyboardProcessor.stateKeys[Lkc.kName] = ! core.keyboardProcessor.stateKeys[Lkc.kName];
}

// End - mirrors _GetKeyEventProperties
return Lkc;
}
Expand Down
8 changes: 7 additions & 1 deletion web/source/osk/visualKeyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ namespace com.keyman.osk {
layers: keyboards.LayoutLayer[];
private layerId: string = "default";
readonly isRTL: boolean;
layerIndex: number;
layerIndex: number = 0; // the index of the default layer

device: Device;
isStatic: boolean = false;
Expand Down Expand Up @@ -1022,6 +1022,12 @@ namespace com.keyman.osk {
layerChangeHandler: text.SystemStoreMutationHandler = function(this: VisualKeyboard,
source: text.MutableSystemStore,
newValue: string) {
// This handler is also triggered on state-key state changes (K_CAPS) that
// may not actually change the layer.
if(this) {
this._UpdateVKShiftStyle();
}

if(source.value != newValue) {
this.layerId = newValue;
let keyman = com.keyman.singleton;
Expand Down