diff --git a/tests/e2e/select-input-source.swift b/tests/e2e/select-input-source.swift index fe8ecf52258..3012e76e8d3 100644 --- a/tests/e2e/select-input-source.swift +++ b/tests/e2e/select-input-source.swift @@ -6,9 +6,27 @@ guard CommandLine.arguments.count == 2 else { let properties = [kTISPropertyInputSourceID: CommandLine.arguments[1] as CFString] as CFDictionary let sources = TISCreateInputSourceList(properties, true).takeRetainedValue() as! [TISInputSource] -guard let source = sources.first else { +guard !sources.isEmpty else { exit(3) } -TISEnableInputSource(source) +func boolProperty(_ source: TISInputSource, _ key: CFString) -> Bool { + guard let raw = TISGetInputSourceProperty(source, key) else { return false } + return unsafeBitCast(raw, to: CFBoolean.self) == kCFBooleanTrue +} + +// Why: one id can expose several entries — a third-party IME publishes a non-selectable +// parent alongside the selectable mode, and `sources.first` can return the parent, which +// then fails TISSelectInputSource with paramErr (-50). Qingg is the case that found this. +let selectable = sources.filter { boolProperty($0, kTISPropertyInputSourceIsSelectCapable) } +guard let source = selectable.first ?? sources.first else { + exit(3) +} + +// Enable every entry for the id, not just the selected one: selecting a mode whose parent +// is still disabled also fails with -50. +for candidate in sources { + TISEnableInputSource(candidate) +} + exit(TISSelectInputSource(source) == noErr ? 0 : 4)