@@ -173,6 +173,7 @@ open class TerminalView: UIScrollView, UITextInputTraits, UIKeyInput, UIScrollVi
173173
174174 // We use this as temporary storage for UITextInput, which we send to the terminal on demand
175175 var textInputStorage : String = " "
176+ var pendingAutoPeriodDeleteWasSpace : Bool = false
176177
177178 // This tracks the marked text, part of the UITextInput protocol, which is used to flag temporary data entry, that might
178179 // be removed afterwards by the input system (input methods will insert approximiations, mark and change on demand)
@@ -1092,11 +1093,39 @@ open class TerminalView: UIScrollView, UITextInputTraits, UIKeyInput, UIScrollVi
10921093 return !textInputStorage. isEmpty
10931094 }
10941095
1095- /*
1096- Soft keyboard input. Hardware keyboard text input is delivered here; special keys are handled in pressesBegan.
1097- */
1098- open func insertText( _ text: String ) {
1099- //uitiLog("insertText(\(text.debugDescription)) \(textInputStateDescription())")
1096+ func normalizedAutoPeriodReplacementText( _ text: String , oldText: Substring , rangeToReplace: TextRange ) -> String ? {
1097+ if text == " . " && pendingAutoPeriodDeleteWasSpace {
1098+ pendingAutoPeriodDeleteWasSpace = false
1099+ return " "
1100+ }
1101+ guard text == " . " else { return nil }
1102+ guard rangeToReplace. endPosition. offset == textInputStorage. count else { return nil }
1103+ guard oldText. count <= 2 else { return nil }
1104+ guard oldText. allSatisfy ( { $0 == " " } ) else { return nil }
1105+ if oldText. count == 1 {
1106+ return " "
1107+ }
1108+ return String ( oldText)
1109+ }
1110+
1111+ private func normalizedAutoPeriodInsertionText( _ text: String , rangeToReplace: TextRange , hadPendingAutoPeriodDelete: Bool ) -> String ? {
1112+ guard text == " . " else { return nil }
1113+ if hadPendingAutoPeriodDelete {
1114+ pendingAutoPeriodDeleteWasSpace = false
1115+ return " "
1116+ }
1117+ pendingAutoPeriodDeleteWasSpace = false
1118+ guard rangeToReplace. isEmpty else { return nil }
1119+ guard rangeToReplace. endPosition. offset == textInputStorage. count else { return nil }
1120+ guard textInputStorage. last == " " else { return nil }
1121+ return " "
1122+ }
1123+
1124+ private func commitTextInput( _ text: String , applyControlModifier: Bool ) {
1125+ let hadPendingAutoPeriodDelete = pendingAutoPeriodDeleteWasSpace
1126+ if text != " . " {
1127+ pendingAutoPeriodDeleteWasSpace = false
1128+ }
11001129
11011130 if tryComposeKoreanFinal ( text) {
11021131 return
@@ -1105,29 +1134,46 @@ open class TerminalView: UIScrollView, UITextInputTraits, UIKeyInput, UIScrollVi
11051134 beginTextInputEdit ( )
11061135
11071136 let rangeToReplace = _markedTextRange ?? _selectedTextRange
1137+ var textToInsert = text
1138+ if let normalized = normalizedAutoPeriodInsertionText ( text, rangeToReplace: rangeToReplace, hadPendingAutoPeriodDelete: hadPendingAutoPeriodDelete) {
1139+ textToInsert = normalized
1140+ }
1141+
11081142 let rangeStartIndex = rangeToReplace. startPosition. offset
1109- textInputStorage. replaceSubrange ( rangeToReplace. fullRange ( in: textInputStorage) , with: text )
1143+ textInputStorage. replaceSubrange ( rangeToReplace. fullRange ( in: textInputStorage) , with: textToInsert )
11101144 _markedTextRange = nil
1111- let insertedPosition = TextPosition ( offset: rangeStartIndex + text . count)
1145+ let insertedPosition = TextPosition ( offset: rangeStartIndex + textToInsert . count)
11121146 _selectedTextRange = TextRange ( from: insertedPosition, to: insertedPosition)
11131147
11141148 endTextInputEdit ( )
11151149
1116- if terminalAccessory? . controlModifier ?? false {
1117- self . send ( applyControlToEventCharacters ( text ) )
1150+ if applyControlModifier && ( terminalAccessory? . controlModifier ?? false ) {
1151+ self . send ( applyControlToEventCharacters ( textToInsert ) )
11181152 terminalAccessory? . controlModifier = false
11191153 } else {
1120- if text == " \n " {
1154+ if textToInsert == " \n " {
11211155 resetInputBuffer ( )
11221156 self . send ( data: returnByteSequence [ 0 ... ] )
11231157 } else {
1124- self . send ( txt: text )
1158+ self . send ( txt: textToInsert )
11251159 }
11261160 }
1127-
1161+
11281162 queuePendingDisplay ( )
11291163 }
11301164
1165+ func insertTextFromAccessory( _ text: String ) {
1166+ commitTextInput ( text, applyControlModifier: false )
1167+ }
1168+
1169+ /*
1170+ Soft keyboard input. Hardware keyboard text input is delivered here; special keys are handled in pressesBegan.
1171+ */
1172+ open func insertText( _ text: String ) {
1173+ //uitiLog("insertText(\(text.debugDescription)) \(textInputStateDescription())")
1174+ commitTextInput ( text, applyControlModifier: true )
1175+ }
1176+
11311177 // this is necessary because something in the iOS IME seems to prevent
11321178 // the sequence "ㅇ", "ㅜ", "ㅇ" from becoming "웅", and instead
11331179 // it becomes "우" followed by "ㅇ"
@@ -1212,6 +1258,7 @@ open class TerminalView: UIScrollView, UITextInputTraits, UIKeyInput, UIScrollVi
12121258 // This is the case when the user hits backspace, but there is no text in the
12131259 // text input buffer. This happens for example when text has been pasted.
12141260 // In that scenario, we should just send the backspace character to the terminal
1261+ pendingAutoPeriodDeleteWasSpace = false
12151262 self . send ( [ backspaceSendsControlH ? 8 : 0x7f ] )
12161263 uitiLog ( " deleteBackward() no text to delete, sending backspace " )
12171264 return
@@ -1220,11 +1267,16 @@ open class TerminalView: UIScrollView, UITextInputTraits, UIKeyInput, UIScrollVi
12201267 beginTextInputEdit ( )
12211268
12221269 rangeStartIndex -= 1
1223- textInputStorage. remove ( at: textInputStorage. index ( textInputStorage. startIndex, offsetBy: rangeStartIndex) )
1270+ let deleteIndex = textInputStorage. index ( textInputStorage. startIndex, offsetBy: rangeStartIndex)
1271+ let deletedChar = textInputStorage [ deleteIndex]
1272+ let deletingAtEnd = rangeStartPosition. offset == textInputStorage. count
1273+ pendingAutoPeriodDeleteWasSpace = deletingAtEnd && deletedChar == " " && _markedTextRange == nil
1274+ textInputStorage. remove ( at: deleteIndex)
12241275 rangeStartPosition = TextPosition ( offset: rangeStartIndex)
12251276
12261277 self . send ( [ backspaceSendsControlH ? 8 : 0x7f ] )
12271278 } else {
1279+ pendingAutoPeriodDeleteWasSpace = false
12281280 beginTextInputEdit ( )
12291281 // Send as many backspaces that are in the range to delete. When on auto-repeat, after a some time
12301282 // pressing the backspace, it will delete chunks of text at a time.
0 commit comments