diff --git a/src/renderer/src/components/terminal-pane/terminal-ime-platform.test.ts b/src/renderer/src/components/terminal-pane/terminal-ime-platform.test.ts index 5b98ed646e9..bc7152d26de 100644 --- a/src/renderer/src/components/terminal-pane/terminal-ime-platform.test.ts +++ b/src/renderer/src/components/terminal-pane/terminal-ime-platform.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest' +import { resolveShortcutPlatform } from '@/lib/shortcut-platform' import { resolveTerminalImePlatform } from './terminal-ime-platform' const DESKTOP_LINUX = @@ -11,6 +12,8 @@ const MACOS = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' const WINDOWS = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' +const FREEBSD = + 'Mozilla/5.0 (X11; FreeBSD amd64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' describe('resolveTerminalImePlatform', () => { it('treats desktop Linux as both Chromium-family and ibus/fcitx-bearing', () => { @@ -44,4 +47,25 @@ describe('resolveTerminalImePlatform', () => { isDesktopLinux: false }) }) + + // Only Windows has a reason to suppress a standalone 229, so an unrecognised desktop + // belongs on the passing side rather than in whichever bucket a UA guess lands it in. + it('treats an unrecognised desktop as Linux', () => { + expect(resolveTerminalImePlatform(FREEBSD)).toEqual({ + isMac: false, + isLinux: true, + isDesktopLinux: true + }) + }) + + it.each([DESKTOP_LINUX, CHROME_OS, ANDROID, MACOS, WINDOWS, FREEBSD])( + 'agrees with the renderer-wide platform mapping (%#)', + (userAgent) => { + const { isMac, isLinux } = resolveTerminalImePlatform(userAgent) + expect({ isMac, isLinux }).toEqual({ + isMac: resolveShortcutPlatform(userAgent) === 'darwin', + isLinux: resolveShortcutPlatform(userAgent) === 'linux' + }) + } + ) }) diff --git a/src/renderer/src/components/terminal-pane/terminal-ime-platform.ts b/src/renderer/src/components/terminal-pane/terminal-ime-platform.ts index ea7765e937f..a42bbc1dbce 100644 --- a/src/renderer/src/components/terminal-pane/terminal-ime-platform.ts +++ b/src/renderer/src/components/terminal-pane/terminal-ime-platform.ts @@ -1,30 +1,34 @@ +import { resolveShortcutPlatform } from '@/lib/shortcut-platform' + export type TerminalImePlatform = { isMac: boolean - /** Chromium on a Linux kernel — ChromeOS and Android included. */ + /** Everything that is neither macOS nor Windows, matching `getShortcutPlatform`. */ isLinux: boolean /** Desktop Linux only — the platforms actually running ibus or fcitx. */ isDesktopLinux: boolean } -// ChromeOS reports `X11; CrOS x86_64`, with no "Linux" anywhere in it, so a plain -// substring test puts it on the Windows side of every policy below. -const LINUX_KERNEL_PLATFORM = /Linux|CrOS/ const NON_DESKTOP_LINUX_PLATFORM = /Android|CrOS/ /** * Splits the two platform questions the terminal's IME policy asks, which are not the * same question and had been sharing one answer. * - * Standalone keydown 229 is Chromium-family behavior, so ChromeOS and Android belong - * with desktop Linux. The candidate-key guards read ibus/fcitx specifics that neither - * shares, so they are scoped tighter. Deriving both here keeps one user agent from - * getting two different platform verdicts in two different files. + * Standalone keydown 229 is really a question about Windows, whose preedit-diff race is + * the only reason to suppress it, so every other platform passes. Sharing the renderer's + * one user-agent mapping is what keeps that set from drifting: enumerating Linux-ish + * user agents here instead is how ChromeOS — which reports `X11; CrOS x86_64`, with no + * "Linux" in it — ended up on the Windows side of this policy while the rest of the + * renderer treated it as Linux. + * + * The candidate-key guards read ibus/fcitx specifics that ChromeOS and Android do not + * share, so they are scoped tighter. That narrowing is the only intended difference. */ export function resolveTerminalImePlatform(userAgent: string): TerminalImePlatform { - const isMac = userAgent.includes('Mac') - const isLinux = !isMac && LINUX_KERNEL_PLATFORM.test(userAgent) + const platform = resolveShortcutPlatform(userAgent) + const isLinux = platform === 'linux' return { - isMac, + isMac: platform === 'darwin', isLinux, isDesktopLinux: isLinux && !NON_DESKTOP_LINUX_PLATFORM.test(userAgent) } diff --git a/src/renderer/src/lib/shortcut-platform.ts b/src/renderer/src/lib/shortcut-platform.ts index 29e4cd757c5..8bde5093517 100644 --- a/src/renderer/src/lib/shortcut-platform.ts +++ b/src/renderer/src/lib/shortcut-platform.ts @@ -1,6 +1,11 @@ -export function getShortcutPlatform(): NodeJS.Platform { - if (navigator.userAgent.includes('Mac')) { +/** Maps a user agent to the platform whose conventions the renderer should follow. */ +export function resolveShortcutPlatform(userAgent: string): NodeJS.Platform { + if (userAgent.includes('Mac')) { return 'darwin' } - return navigator.userAgent.includes('Windows') ? 'win32' : 'linux' + return userAgent.includes('Windows') ? 'win32' : 'linux' +} + +export function getShortcutPlatform(): NodeJS.Platform { + return resolveShortcutPlatform(navigator.userAgent) }