Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/mobile/modules/t3-terminal/ios/T3TerminalModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class T3TerminalModule: Module {
// Bumped when native hardware-keyboard handling changes; surfaced in the JS debug
// logs so a stale native binary is distinguishable from a broken key pipeline.
Constants([
"hardwareKeyRevision": 2,
"hardwareKeyRevision": 3,
])

View(T3TerminalView.self) {
Expand Down
21 changes: 19 additions & 2 deletions apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,21 @@ private enum TerminalHardwareKeyEncoder {
}
}

private enum TerminalInputSequence {
/// Terminal Enter is carriage return. Sending line feed instead is Ctrl+J,
/// which raw-mode TUIs may interpret as the literal J key.
static let carriageReturn = "\r"

static func normalizingReturn(_ input: String) -> String {
switch input {
case "\n", "\r\n":
return carriageReturn
default:
return input
}
}
}

private final class TerminalInputField: UITextField {
var onDeleteBackward: (() -> Void)?
var onInsert: ((String) -> Void)?
Expand Down Expand Up @@ -352,15 +367,17 @@ public final class T3TerminalView: ExpoView, UITextFieldDelegate {

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if !string.isEmpty {
emitInput(string)
// Some software keyboards deliver Return through this delegate instead of
// textFieldShouldReturn, so normalize that path too.
emitInput(TerminalInputSequence.normalizingReturn(string))
return false
}

return false
}

public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
emitInput("\n")
emitInput(TerminalInputSequence.carriageReturn)
textField.text = ""
return false
}
Expand Down
3 changes: 2 additions & 1 deletion apps/mobile/src/features/terminal/NativeTerminalSurface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: Ter
onSubmitEditing={(event) => {
const text = event.nativeEvent.text;
if (text.length > 0) {
props.onInput(`${text}\n`);
// Terminal Enter is CR. LF is Ctrl+J and raw-mode TUIs can treat it as J.
props.onInput(`${text}\r`);
}
}}
/>
Expand Down
Loading