diff --git a/src/DodoSSH.Client.Android/Views/TerminalScreen.axaml.cs b/src/DodoSSH.Client.Android/Views/TerminalScreen.axaml.cs index 9af3e31..40b562d 100644 --- a/src/DodoSSH.Client.Android/Views/TerminalScreen.axaml.cs +++ b/src/DodoSSH.Client.Android/Views/TerminalScreen.axaml.cs @@ -5,6 +5,7 @@ using Avalonia.Controls; using Avalonia.Layout; using Avalonia.Markup.Xaml; using Avalonia.Media; +using Avalonia.Platform; using DodoSSH.Client.Shell.ViewModels; @@ -70,16 +71,44 @@ internal sealed partial class TerminalScreen : UserControl BuildAccessoryRow(); + var renderer = this.FindControl("Renderer")!; + + renderer.EnvironmentRequested += OnRendererEnvironmentRequested; + // The URL is only known once the loopback listener has bound a port, so it cannot be set in XAML. DataContextChanged += (_, _) => { if (DataContext is MainWindowViewModel shell) { - this.FindControl("Renderer")!.Source = shell.TerminalPageUrl; + renderer.Source = shell.TerminalPageUrl; } }; } + /// + /// Takes the browser gestures back off a surface that is not a web page. + /// + /// + /// + /// A terminal is a fixed grid that the fit addon sizes to the window. Pinch-zoom breaks that in both + /// directions at once: the visible width stops matching the column count the remote was told about, so + /// wrapping goes wrong, and the part of the grid under the thumb is no longer the part that gets the + /// tap. It is the WebView's own zoom rather than anything the page asked for. + /// + /// + /// This is the knob that works. user-scalable=no in the page's viewport tag does not: Blink has + /// ignored it since Chrome 48 for accessibility reasons and WebView follows Blink. The page still + /// carries the viewport tag, for the layout width rather than the zoom — see WebAssets/terminal.html. + /// + /// + private static void OnRendererEnvironmentRequested(object? sender, EventArgs e) + { + if (e is AndroidWebViewEnvironmentRequestedEventArgs android) + { + android.BuiltInZoomControls = false; + } + } + private void BuildAccessoryRow() { var row = this.FindControl("AccessoryKeys")!; diff --git a/src/DodoSSH.Client.Shell/WebAssets/terminal.css b/src/DodoSSH.Client.Shell/WebAssets/terminal.css index 27d776f..06c5a47 100644 --- a/src/DodoSSH.Client.Shell/WebAssets/terminal.css +++ b/src/DodoSSH.Client.Shell/WebAssets/terminal.css @@ -23,6 +23,20 @@ body { background: var(--dodo-background); color: var(--dodo-foreground); font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace; + + /* + Touch rules, and they only ever matter on the phone — a desktop WebView has no gestures to give + away. pan-y keeps the one gesture a terminal wants, dragging the scrollback, and refuses the two + it must not have: pinch-zoom, and the double-tap zoom that would otherwise fire on every attempt + to place the cursor. + + text-size-adjust stops Android's own font inflation. It resizes text it judges too small without + telling the page, which in a terminal means characters that no longer match the cell grid the fit + addon measured — the rows stop lining up and the columns are wrong by a character or two. + */ + touch-action: pan-y; + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; } #root { diff --git a/src/DodoSSH.Client.Shell/WebAssets/terminal.html b/src/DodoSSH.Client.Shell/WebAssets/terminal.html index 8003722..ff0b9b0 100644 --- a/src/DodoSSH.Client.Shell/WebAssets/terminal.html +++ b/src/DodoSSH.Client.Shell/WebAssets/terminal.html @@ -4,6 +4,23 @@ DodoSSH terminal + + +