Skip to content

Commit

Permalink
Merge pull request #10445 from keymanapp/fix/android/hardware-mnemoni…
Browse files Browse the repository at this point in the history
…c-mapping
  • Loading branch information
jahorton authored Jan 23, 2024
2 parents 237001f + 68d97b4 commit 6d79aa0
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 43 deletions.
41 changes: 2 additions & 39 deletions web/src/app/browser/src/hardwareEventKeyboard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Codes, DeviceSpec, KeyEvent, KeyMapping, Keyboard, KeyboardProcessor } from '@keymanapp/keyboard-processor';

import { HardKeyboard } from 'keyman/engine/main';
import { HardKeyboard, processForMnemonicsAndLegacy } from 'keyman/engine/main';
import { DomEventTracker } from 'keyman/engine/events';
import { DesignIFrame, nestedInstanceOf } from 'keyman/engine/element-wrappers';
import { eventOutputTarget, outputTargetForElement } from 'keyman/engine/attachment';
Expand Down Expand Up @@ -186,48 +186,11 @@ export function preprocessKeyboardEvent(e: KeyboardEvent, keyboardState: Keyboar
isSynthetic: false
});

// Mnemonic handling.
if(activeKeyboard && activeKeyboard.isMnemonic) {
// The following will never set a code corresponding to a modifier key, so it's fine to do this,
// which may change the value of Lcode, here.

s.setMnemonicCode(e.getModifierState("Shift"), e.getModifierState("CapsLock"));
}
// The 0x6F used to be 0x60 - this adjustment now includes the chiral alt and ctrl modifiers in that check.
let LisVirtualKeyCode = (typeof e.charCode != 'undefined' && e.charCode != null && (e.charCode == 0 || (Lmodifiers & 0x6F) != 0));
s.LisVirtualKey = LisVirtualKeyCode || e.type != 'keypress';

// Other minor physical-keyboard adjustments
if(activeKeyboard && !activeKeyboard.isMnemonic) {
// Positional Layout

/* 13/03/2007 MCD: Swedish: Start mapping of keystroke to US keyboard */
var Lbase = KeyMapping.languageMap[keyboardState.baseLayout];
if(Lbase && Lbase['k'+s.Lcode]) {
s.Lcode=Lbase['k'+s.Lcode];
}
/* 13/03/2007 MCD: Swedish: End mapping of keystroke to US keyboard */

// The second conditional component (re 0x60): if CTRL or ALT is held down...
// Do not remap for legacy keyboard compatibility, do not pass Go, do not collect $200.
// This effectively only permits `default` and `shift` for legacy keyboards.
//
// Third: DO, however, track direct presses of any main modifier key. The OSK should
// reflect the current modifier state even for legacy keyboards.
if(!activeKeyboard.definesPositionalOrMnemonic && !(s.Lmodifiers & 0x60) && !s.isModifier) {
// Support version 1.0 KeymanWeb keyboards that do not define positional vs mnemonic
s = new KeyEvent({
Lcode: KeyMapping._USKeyCodeToCharCode(s),
Lmodifiers: 0,
LisVirtualKey: false,
vkCode: s.Lcode, // Helps to merge OSK and physical keystroke control paths.
Lstates: s.Lstates,
kName: '',
device: device,
isSynthetic: false
});
}
}
s = processForMnemonicsAndLegacy(s, activeKeyboard, keyboardState.baseLayout);

let processedEvent = new KeyEvent(s);
processedEvent.source = e;
Expand Down
4 changes: 4 additions & 0 deletions web/src/app/webview/src/keymanEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export default class KeymanEngine extends KeymanEngineBase<WebviewConfiguration,
this.core.keyboardProcessor.beepHandler = this.beepKeyboard;
}

this.contextManager.on('keyboardchange', (kbd) => {
this.hardKeyboard.activeKeyboard = kbd?.keyboard;
});

this.contextManager.initialize();

const oskConfig: ViewConfiguration = {
Expand Down
9 changes: 7 additions & 2 deletions web/src/app/webview/src/passthroughKeyboard.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { DeviceSpec, KeyEvent, ManagedPromise } from '@keymanapp/keyboard-processor';
import { DeviceSpec, Keyboard, KeyEvent, ManagedPromise } from '@keymanapp/keyboard-processor';

import { HardKeyboard } from 'keyman/engine/main';
import { HardKeyboard, processForMnemonicsAndLegacy } from 'keyman/engine/main';

export default class PassthroughKeyboard extends HardKeyboard {
readonly baseDevice: DeviceSpec;
public activeKeyboard: Keyboard;

constructor(baseDevice: DeviceSpec) {
super();
Expand Down Expand Up @@ -37,6 +38,10 @@ export default class PassthroughKeyboard extends HardKeyboard {
isSynthetic: false // is not an OSK keystroke.
});

// 'us' is our default base layout; our distributed engine doesn't support
// changing the assumed base keyboard for mnemonics.
Lkc = processForMnemonicsAndLegacy(Lkc, this.activeKeyboard, 'us');

const promise = new ManagedPromise<Boolean>();

try {
Expand Down
47 changes: 46 additions & 1 deletion web/src/engine/main/src/hardKeyboard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import EventEmitter from "eventemitter3";
import { type KeyEvent, type RuleBehavior } from "@keymanapp/keyboard-processor";
import { Keyboard, KeyMapping, KeyEvent, type RuleBehavior, Codes } from "@keymanapp/keyboard-processor";
import { KeyEventSourceInterface } from 'keyman/engine/events';

interface EventMap {
Expand All @@ -11,6 +11,51 @@ interface EventMap {

export default class HardKeyboard extends EventEmitter<EventMap> implements KeyEventSourceInterface<EventMap> { }

export function processForMnemonicsAndLegacy(s: KeyEvent, activeKeyboard: Keyboard, baseLayout: string): KeyEvent {
const modCodes = Codes.modifierCodes;

// Mnemonic handling.
if(activeKeyboard && activeKeyboard.isMnemonic) {
// The following will never set a code corresponding to a modifier key, so it's fine to do this,
// which may change the value of Lcode, here.

s.setMnemonicCode(!!(s.Lmodifiers & modCodes.SHIFT), !!(s.Lmodifiers & modCodes.CAPS));
}

// Other minor physical-keyboard adjustments
if(activeKeyboard && !activeKeyboard.isMnemonic) {
// Positional Layout

/* 13/03/2007 MCD: Swedish: Start mapping of keystroke to US keyboard */
var Lbase = KeyMapping.languageMap[baseLayout];
if(Lbase && Lbase['k'+s.Lcode]) {
s.Lcode=Lbase['k'+s.Lcode];
}
/* 13/03/2007 MCD: Swedish: End mapping of keystroke to US keyboard */

// The second conditional component (re 0x60): if CTRL or ALT is held down...
// Do not remap for legacy keyboard compatibility, do not pass Go, do not collect $200.
// This effectively only permits `default` and `shift` for legacy keyboards.
//
// Third: DO, however, track direct presses of any main modifier key. The OSK should
// reflect the current modifier state even for legacy keyboards.
if(!activeKeyboard.definesPositionalOrMnemonic && !(s.Lmodifiers & 0x60) && !s.isModifier) {
// Support version 1.0 KeymanWeb keyboards that do not define positional vs mnemonic
s = new KeyEvent({
Lcode: KeyMapping._USKeyCodeToCharCode(s),
Lmodifiers: 0,
LisVirtualKey: false,
vkCode: s.Lcode, // Helps to merge OSK and physical keystroke control paths.
Lstates: s.Lstates,
kName: '',
device: s.device,
isSynthetic: false
});
}
}

return s;
}
// Intended design:
// - KeyEventKeyboard: website-integrated handler for hardware-keystroke input; interprets DOM events.
// - app/web
Expand Down
2 changes: 1 addition & 1 deletion web/src/engine/main/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { EngineConfiguration, InitOptionDefaults, InitOptionSpec } from './engineConfiguration.js';
export { ContextManagerBase, ContextManagerConfiguration } from './contextManagerBase.js';
export { default as HardKeyboard } from './hardKeyboard.js';
export { default as HardKeyboard, processForMnemonicsAndLegacy } from './hardKeyboard.js';
export { default as KeyboardInterface } from './keyboardInterface.js';
export { default as KeymanEngine } from './keymanEngine.js';
export { LegacyAPIEvents } from './legacyAPIEvents.js';
Expand Down

0 comments on commit 6d79aa0

Please sign in to comment.