Browse Source

Merge pull request #11010 from AvaloniaUI/mozilla-hacks-clipboard

Add "readClipboardText" workaround for Mozilla
pull/11012/head
Max Katz 3 years ago
committed by GitHub
parent
commit
40b5c3b178
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Browser/Avalonia.Browser/AvaloniaView.cs
  2. 5
      src/Browser/Avalonia.Browser/Interop/InputHelper.cs
  3. 59
      src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts

2
src/Browser/Avalonia.Browser/AvaloniaView.cs

@ -90,6 +90,8 @@ namespace Avalonia.Browser
_topLevel.Renderer.Start();
InputHelper.InitializeBackgroundHandlers();
InputHelper.SubscribeKeyEvents(
_containerElement,
OnKeyDown,

5
src/Browser/Avalonia.Browser/Interop/InputHelper.cs

@ -81,7 +81,10 @@ internal static partial class InputHelper
[JSImport("InputHelper.setBounds", AvaloniaModule.MainModuleName)]
public static partial void SetBounds(JSObject htmlElement, int x, int y, int width, int height, int caret);
[JSImport("globalThis.navigator.clipboard.readText")]
[JSImport("InputHelper.initializeBackgroundHandlers", AvaloniaModule.MainModuleName)]
public static partial void InitializeBackgroundHandlers();
[JSImport("InputHelper.readClipboardText", AvaloniaModule.MainModuleName)]
public static partial Task<string> ReadClipboardTextAsync();
[JSImport("globalThis.navigator.clipboard.writeText")]

59
src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts

@ -19,14 +19,68 @@ enum RawInputModifiers {
PenBarrelButton = 2048
}
/*
* This is a hack to handle Mozilla clipboard events in a more convinient way for framework users.
* In the browser, events go in order KeyDown -> Paste -> KeyUp.
* On KeyDown we trigger Avalonia handlers, which might execute readClipboardText.
* When readClipboardText was executed, we mark ClipboardState as Pending and setup clipboard promise,
* which will un-handle KeyDown event, basically allowing browser to pass a Paste event properly.
* On actual Paste event we execute promise callbacks, resuming async operation, and returning pasted text to the app.
* Note #1, on every KeyUp event we will reset all the state and reject pending promises if any, as this event it expected to come after Paste.
* Note #2, whole this code will be executed only on legacy browsers like Mozilla, where clipboard.readText is not available.
* Note #3, with all of these hacks Clipboard.ReadText will still work only on actual "paste" gesture initiated by user.
* */
enum ClipboardState {
None,
Ready,
Pending
}
export class InputHelper {
static clipboardState: ClipboardState = ClipboardState.None;
static resolveClipboard?: any;
static rejectClipboard?: any;
public static initializeBackgroundHandlers() {
if (this.clipboardState !== ClipboardState.None) {
return;
}
globalThis.addEventListener("paste", (args: any) => {
if (this.clipboardState === ClipboardState.Pending) {
this.resolveClipboard(args.clipboardData.getData("text"));
}
});
this.clipboardState = ClipboardState.Ready;
}
public static async readClipboardText(): Promise<string> {
if (globalThis.navigator.clipboard.readText) {
return await globalThis.navigator.clipboard.readText();
} else {
try {
return await new Promise<any>((resolve, reject) => {
this.clipboardState = ClipboardState.Pending;
this.resolveClipboard = resolve;
this.rejectClipboard = reject;
});
} finally {
this.clipboardState = ClipboardState.Ready;
this.resolveClipboard = null;
this.rejectClipboard = null;
}
}
}
public static subscribeKeyEvents(
element: HTMLInputElement,
keyDownCallback: (code: string, key: string, modifiers: RawInputModifiers) => boolean,
keyUpCallback: (code: string, key: string, modifiers: RawInputModifiers) => boolean) {
const keyDownHandler = (args: KeyboardEvent) => {
if (keyDownCallback(args.code, args.key, this.getModifiers(args))) {
args.preventDefault();
if (this.clipboardState !== ClipboardState.Pending) {
args.preventDefault();
}
}
};
element.addEventListener("keydown", keyDownHandler);
@ -35,6 +89,9 @@ export class InputHelper {
if (keyUpCallback(args.code, args.key, this.getModifiers(args))) {
args.preventDefault();
}
if (this.rejectClipboard) {
this.rejectClipboard();
}
};
element.addEventListener("keyup", keyUpHandler);

Loading…
Cancel
Save