Skip to content

Commit

Permalink
Fix false on enter trigger when using IME. (#593)
Browse files Browse the repository at this point in the history
The isComposing field tells us if we are using an input method editor (IME) which
will display a menu of characters that can't be represented on a standard QWERTY
keyboard. The user can select from this menu by pressing "enter" or clicking the
menu item. The user will then need to press "enter" to confirm the selection (at
least on MacOS).

If we do not check isComposing on key up, this will trigger the Mesop on enter
event.

If we check isComposing on key up, the enter confirmation will trigger the Mesop
on enter event since isComposing becomes false on key up.

We need to track isComposing with the key down event since this will trigger the
on enter event when "enter" is pressed again (when the IME is inactive and
a selection has been made and applied).

Safari has a bug where the order of operations for isComposing is in a different
order. See https://bugs.webkit.org/show_bug.cgi?id=165004.

In order to work around this issue, we need to count expectedIsComposingCount
equals false twice on Safari rather than just once.
  • Loading branch information
richard-to authored Jul 10, 2024
1 parent 34a02e1 commit 3ac96ac
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
1 change: 1 addition & 0 deletions mesop/components/input/input.ng.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
(blur)="onBlur($event)"
(input)="onInput($event)"
(keyup)="onKeyUp($event)"
(keydown)="onKeyDown($event)"
/>
}
</mat-form-field>
Expand Down
47 changes: 45 additions & 2 deletions mesop/components/input/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export class InputComponent {
@Input() style!: Style;
private _config!: InputType;
private inputSubject = new Subject<Event>();

private isComposingCount: number = 1;
private expectedIsComposingCount: number = 1;
constructor(private readonly channel: Channel) {
this.inputSubject
.pipe(
Expand All @@ -35,6 +36,14 @@ export class InputComponent {
debounceTime(150),
)
.subscribe((event) => this.onInputDebounced(event));
// See keyDown event for explanation for why we have a special case for Safari.
if (
navigator.userAgent.indexOf('Safari') > -1 &&
navigator.userAgent.indexOf('Chrome') === -1
) {
this.expectedIsComposingCount = 2;
this.isComposingCount = 2;
}
}

ngOnDestroy(): void {
Expand Down Expand Up @@ -84,7 +93,12 @@ export class InputComponent {
}

onKeyUp(event: Event): void {
if ((event as KeyboardEvent).key === 'Enter') {
// See onKeyDown event for why need to check this.isComposingCount.
const keyboardEvent = event as KeyboardEvent;
if (
keyboardEvent.key === 'Enter' &&
this.isComposingCount === this.expectedIsComposingCount
) {
const userEvent = new UserEvent();
userEvent.setHandlerId(this.config().getOnEnterHandlerId()!);
userEvent.setStringValue((event.target as HTMLInputElement).value);
Expand All @@ -93,6 +107,35 @@ export class InputComponent {
}
}

onKeyDown(event: Event): void {
// The isComposing field tells us if we are using an input method editor (IME) which
// will display a menu of characters that can't be represented on a standard QWERTY
// keyboard. The user can select from this menu by pressing "enter" or clicking the
// menu item. The user will then need to press "enter" to confirm the selection (at
// least on MacOS).
//
// If we do not check isComposing on key up, this will trigger the Mesop on enter
// event.
//
// If we check isComposing on key up, the enter confirmation will trigger the Mesop
// on enter event since isComposing becomes false on key up.
//
// We need to track isComposing with the key down event since this will trigger the
// on enter event when "enter" is pressed again (when the IME is inactive and
// a selection has been made and applied).
//
// Safari has a bug where the order of operations for isComposing is in a different
// order. See https://bugs.webkit.org/show_bug.cgi?id=165004.
//
// In order to work around this issue, we need to count expectedIsComposingCount
// equals false twice on Safari rather than just once.
if ((event as KeyboardEvent).isComposing) {
this.isComposingCount = 0;
} else if (this.isComposingCount < this.expectedIsComposingCount) {
this.isComposingCount += 1;
}
}

onBlur(event: Event): void {
const userEvent = new UserEvent();
userEvent.setHandlerId(this.config().getOnBlurHandlerId()!);
Expand Down

0 comments on commit 3ac96ac

Please sign in to comment.