The earlier UIKeyInput conformance was declared in a separate extension. ObjC protocol conformance via Swift extension is fragile when the protocol inherits another @objc protocol (UIKeyInput inherits UITextInputTraits) — the runtime didn't always pick up insertText:, so the on-screen keyboard came up but characters never reached controller.type(_:). Fix: declare UIKeyInput conformance directly on FramebufferUIView's class declaration, with insertText / deleteBackward / hasText as native members. Also caught and fixed by the new UI test: - The toolbar's keyboard-icon button had a 20×13 hit region (SF Symbol size) even though the visual frame was 34×34 — XCUI taps couldn't land on it reliably. .contentShape(Rectangle()) widens the hit area to the frame. - accessibilityValue is reserved by iOS for UIKeyInput-classed views (treats them as TextView), so a separate hidden "fb-diag" accessibility probe records keyboard plumbing events for the test to verify. Tests: - KeyboardInputTests (5): pure mapping from String → X11 keysym down/up pairs - ScreensUITests.testSoftwareKeyboardSendsCharactersToFramebuffer: opens a session, taps the keyboard toggle, types "hi" via the system keyboard, and asserts the framebuffer's diagnostic probe records [ins:h] and [ins:i] — proving the chars reach controller.type(_:) - A SwiftUI state probe (sessionview-state) verifies the binding flips, which guards against future tap-routing regressions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
42 lines
1.5 KiB
Swift
42 lines
1.5 KiB
Swift
import Testing
|
|
@testable import VNCCore
|
|
import Foundation
|
|
|
|
@Suite struct KeyboardInputTests {
|
|
@Test func plainAsciiProducesDownUpPairs() {
|
|
let events = SessionController.keyEvents(for: "ab")
|
|
#expect(events.count == 4)
|
|
#expect(events[0] == .init(keysym: 0x61, isDown: true))
|
|
#expect(events[1] == .init(keysym: 0x61, isDown: false))
|
|
#expect(events[2] == .init(keysym: 0x62, isDown: true))
|
|
#expect(events[3] == .init(keysym: 0x62, isDown: false))
|
|
}
|
|
|
|
@Test func uppercaseAsciiSendsDistinctKeysym() {
|
|
let events = SessionController.keyEvents(for: "A")
|
|
#expect(events.count == 2)
|
|
#expect(events[0] == .init(keysym: 0x41, isDown: true))
|
|
#expect(events[1] == .init(keysym: 0x41, isDown: false))
|
|
}
|
|
|
|
@Test func spaceMapsToAsciiSpace() {
|
|
let events = SessionController.keyEvents(for: " ")
|
|
#expect(events.count == 2)
|
|
#expect(events[0].keysym == 0x20)
|
|
}
|
|
|
|
@Test func newlineMapsToX11Return() {
|
|
let events = SessionController.keyEvents(for: "\n")
|
|
#expect(events.count == 2)
|
|
#expect(events[0] == .init(keysym: 0xFF0D, isDown: true))
|
|
#expect(events[1] == .init(keysym: 0xFF0D, isDown: false))
|
|
}
|
|
|
|
@Test func passwordWithMixedCaseAndDigitsAndPunctuation() {
|
|
let events = SessionController.keyEvents(for: "Hi!7")
|
|
let downKeys = events.filter(\.isDown).map(\.keysym)
|
|
// H=0x48, i=0x69, !=0x21, 7=0x37
|
|
#expect(downKeys == [0x48, 0x69, 0x21, 0x37])
|
|
}
|
|
}
|