Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Press/hold Shift modifier instead of toggle when using with physical keyboard, and fix rapid toggling of Shift on Windows #2069

Merged
merged 2 commits into from
Jul 21, 2023
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
3 changes: 1 addition & 2 deletions src/editor-mathfield/keyboard-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,8 @@ export function onInput(
// David Bowie emoji: 👨🏻‍🎤
let graphemes = splitGraphemes(text);

// Check if virtual keyboard is visible and the shift key is pressed
const keyboard = window.mathVirtualKeyboard;
if (keyboard?.visible && keyboard.isShifted) {
if (keyboard?.isShifted) {
graphemes =
typeof graphemes === 'string'
? graphemes.toUpperCase()
Expand Down
9 changes: 5 additions & 4 deletions src/virtual-keyboard/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,7 @@ function handlePointerDown(ev: PointerEvent) {
// Is it the Shift key?
if (isShiftKey(keycap)) {
target.classList.add('is-active');
keyboard.incrementShiftPress();
keyboard.shiftPressCount++;
}

if (keycap.variants) {
Expand Down Expand Up @@ -1107,7 +1107,7 @@ function handleVirtualKeyboardEvent(controller) {
if (ev.type === 'pointercancel') {
target.classList.remove('is-pressed');
if (isShiftKey(keycap)) {
keyboard.decrementShiftPress();
keyboard.shiftPressCount--;
// Because of capslock, we may not have changed status
target.classList.toggle('is-active', keyboard.isShifted);
}
Expand All @@ -1118,7 +1118,7 @@ function handleVirtualKeyboardEvent(controller) {
if (ev.type === 'pointerleave' && ev.target === target) {
target.classList.remove('is-pressed');
if (isShiftKey(keycap)) {
keyboard.decrementShiftPress();
keyboard.shiftPressCount--;
// Because of capslock, we may not have changed status
target.classList.toggle('is-active', keyboard.isShifted);
}
Expand Down Expand Up @@ -1150,7 +1150,8 @@ function handleVirtualKeyboardEvent(controller) {
} else executeKeycapCommand(keycap.shift);
} else executeKeycapCommand(keycap);

if (keyboard.shiftPressCount === 1) keyboard.resetShiftPress();
if (keyboard.shiftPressCount === 1 && !(ev as MouseEvent).shiftKey)
keyboard.shiftPressCount = 0;
}
controller.abort();
ev.preventDefault();
Expand Down
86 changes: 27 additions & 59 deletions src/virtual-keyboard/virtual-keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,64 +72,29 @@ export class VirtualKeyboard implements VirtualKeyboardInterface, EventTarget {
newActive.classList.add('is-visible');
}

if (this.isShifted) this.render();
}

private _isCapslock = false;
get isCapslock(): boolean {
return this._isCapslock;
}
set isCapslock(val: boolean) {
this._element?.classList.toggle('is-caps-lock', this.shiftPressCount === 2);

if (val === this._isCapslock) return;

this._isCapslock = val;
this.isShifted = val;
this.render();
}

/** `0`: not pressed
*
/**
* `0`: not pressed
* `1`: Shift is locked for next char only
*
* `2`: Shift is locked for all characters
*/
private _shiftPressCount: 0 | 1 | 2 = 0;

get shiftPressCount(): 0 | 1 | 2 {
get shiftPressCount(): typeof this._shiftPressCount {
return this._shiftPressCount;
}

/** Increments `_shiftPressCount` by `1`, and handle the appropriate related behavior for each val */
incrementShiftPress(): void {
if (++this._shiftPressCount > 2) this.resetShiftPress();
else this.isCapslock = true;
}

/** Decrements `_shiftPressCount` by `1`, and sets `isCapslock` to `false` if reaches `0` */
decrementShiftPress(): void {
this._shiftPressCount = Math.max(--this._shiftPressCount, 0) as 0 | 1 | 2;
if (this._shiftPressCount === 0) this.isCapslock = false;
}
set shiftPressCount(count: typeof this._shiftPressCount) {
this._shiftPressCount = count > 2 || count < 0 ? 0 : count;
this._element?.classList.toggle('is-caps-lock', this.shiftPressCount === 2);

/** Resets `_shiftPressCount` to `0`, and sets `isCapslock` to `false` */
resetShiftPress(): void {
this._shiftPressCount = 0;
this.isCapslock = false;
this.render();
}

private _isShifted = false;
get isShifted(): boolean {
return this._isShifted;
}

set isShifted(shifted: boolean) {
if (this._isCapslock) shifted = true;
if (this._isShifted === shifted) return;

this._isShifted = shifted;

this.render();
return this._shiftPressCount > 0;
}

resetKeycapRegistry(): void {
Expand Down Expand Up @@ -363,7 +328,6 @@ export class VirtualKeyboard implements VirtualKeyboardInterface, EventTarget {
if (typeof x === 'function') x(event);
else x?.handleEvent(event);
});

return !event.defaultPrevented;
}

Expand Down Expand Up @@ -505,14 +469,12 @@ export class VirtualKeyboard implements VirtualKeyboardInterface, EventTarget {
window.addEventListener('keydown', this, { capture: true });
window.addEventListener('keyup', this, { capture: true });

this.currentLayer = this.latentLayer;

this.render();

this._element?.classList.toggle(
'is-caps-lock',
this.shiftPressCount === 2
);

this.currentLayer = this.latentLayer;
}

this._visible = true;
Expand Down Expand Up @@ -600,7 +562,13 @@ export class VirtualKeyboard implements VirtualKeyboardInterface, EventTarget {
this.container?.appendChild(this.element);
}

handleEvent(evt: Event): void {
handleEvent(
evt:
| (MessageEvent<VirtualKeyboardMessage> & { type: 'message' })
| (PointerEvent & { type: 'contextmenu' | 'mouseup' })
| (KeyboardEvent & { type: 'keydown' | 'keyup' })
| (FocusEvent & { type: 'blur' })
): void {
if (isVirtualKeyboardMessage(evt)) {
if (!validateOrigin(evt.origin, this.originValidator)) {
throw new DOMException(
Expand Down Expand Up @@ -631,24 +599,24 @@ export class VirtualKeyboard implements VirtualKeyboardInterface, EventTarget {
// press. Restore the userSelect on mouse up
document.body.style.userSelect = '';

this.isShifted = false;
this.shiftPressCount = 0;
break;

case 'contextmenu':
if ((evt as PointerEvent).button !== 2) evt.preventDefault();
if (evt.button !== 2) evt.preventDefault();
break;

case 'keydown': {
const kev = evt as KeyboardEvent;
if (kev.key === 'Shift') this.incrementShiftPress();
if (evt.key === 'Shift' && !evt.repeat) this.shiftPressCount = 1;
break;
}

case 'keyup': {
const kev = evt as KeyboardEvent;
if (kev.key !== 'Shift' && this._shiftPressCount === 1) {
this.isCapslock = false;
this._shiftPressCount = 0;
}
if (
evt.key === 'Shift' ||
(!evt.getModifierState('Shift') && this.shiftPressCount !== 2)
)
this.shiftPressCount = 0;
break;
}
}
Expand Down