Swift Why Strcmp of Backspace Returns -92

Swift why strcmp of backspace returns -92?

Let's analyze a little bit the code and the data that flows through that code:

  1. string is an empty string, as when you delete a character, the textfield tries to replace it by "nothing" (an empty string)
  2. due to #1, char holds only the string terminator, which is \0, in memory: [0]
  3. "\\b" translates to the \b string, in memory: [92, 98]
  4. due to #2 and #3, strcmp returns 0 - 92 => -92.

Not sure why people use this "algorithm", when they could simply check for the emptiness of the string parameter. I assume they firstly tried to use the \b escape sequence, which doesn't seem to be a valid one, so they added an extra \ character, which compiled, but resulted in an incorrect escape sequence, as \\ is the escaping sequence for the backslash character, resulting in the b part being represented as the plain letter.

Seems that backspace is not reported by the delegate method, instead the delegate method is asked to operate on strings. Detecting the actual key press might need some UIEvent/RunLoop hooks.

Note that an empty string passed to textField(_,shouldChangeCharactersIn:,replacementString:) doesn't always mean that backspace was presset, a cut operation might result too in an empty string being sent to the delegate. You could try and check the range and assume that for a range of 1 backspace was pressed, however the user can also cut one character...

Completely disable 'backspace' being pressed Swift

You need to simply implement textView(_:shouldChangeTextIn:replacementText:) and check for empty replacementText.

Empty replacementText == backspace pressed

If the text is Empty 1return false. Elsereturn true`.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text.isEmpty {
return false
}
return true
}

Detect backspace Event in UITextField

Swift 4.2

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
}
}
return true
}

Older Swift version

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")

if (isBackSpace == -92) {
println("Backspace was pressed")
}
return true
}

Secure TextField clears whole text, on clearing single character using backspace

You need to detect backspace tapped and then remove last element from string with using textField delegate

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")

if (isBackSpace == -92) {
print("Backspace pressed")
}
return true
}

Dont forget to add UITextFieldDelegate to your ViewController

Allow Backspace with character set

When the user taps the backspace, string will be the empty string. So rangeOfCharacter will be nil so your code returns false preventing the backspace from working.

Try this:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return string.isEmpty || string.rangeOfCharacter(from: CharacterSet.letter) != nil
}

textfield backspace action identify when textfield is empty?

followed by @Marmik Shah and @Prashant Tukadiya answer here I add my answer , for quick answer I taken the some code from here

step 1 :

create the IBOutletCollection for your all textfields as well as don't forget to set the tag in all textfields in the sequence order, for e.g [1,2,3,4,5,6]

class ViewController: UIViewController{

@IBOutlet var OTPTxtFields: [MyTextField]! // as well as set the tag for textfield in the sequence order

override func viewDidLoad() {
super.viewDidLoad()

//change button color and other options
OTPTxtFields.forEach { $0.textColor = .red; $0.backspaceTextFieldDelegate = self }
OTPTxtFields.first.becomeFirstResponder()
}

step 2 :

in your current page UITextField delegate method

extension ViewController : UITextFieldDelegate, MyTextFieldDelegate {

func textFieldDidEnterBackspace(_ textField: MyTextField) {
guard let index = OTPTxtFields.index(of: textField) else {
return
}

if index > 0 {
OTPTxtFields[index - 1].becomeFirstResponder()
} else {
view.endEditing(true)
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newString = ((textField.text)! as NSString).replacingCharacters(in: range, with: string)


if newString.count < 2 && !newString.isEmpty {
textFieldShouldReturnSingle(textField, newString : newString)
// return false
}

return newString.count < 2 || string == ""
//return true
}
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
return false
}

return true
}
func textFieldShouldReturnSingle(_ textField: UITextField, newString : String)
{
let nextTag: Int = textField.tag + 1
textField.text = newString
let nextResponder: UIResponder? = textField.superview?.viewWithTag(nextTag)
if let nextR = nextResponder
{
// Found next responder, so set it.

nextR.becomeFirstResponder()
}
else
{
// Not found, so remove keyboard.
textField.resignFirstResponder()
callOTPValidate()
}
}

}

Step 3:

create the textfield class for access the backward function

class MyTextField: UITextField {
weak var myTextFieldDelegate: MyTextFieldDelegate?

override func deleteBackward() {
if text?.isEmpty ?? false {
myTextFieldDelegate?.textFieldDidEnterBackspace(self)
}

super.deleteBackward()
}

}

protocol MyTextFieldDelegate: class {
func textFieldDidEnterBackspace(_ textField: MyTextField)
}

step - 4

finally follow the @Marmik Shah answer for custom class for your UITextField

Sample Image

Step 5

get the values from each textfield use this

func callOTPValidate(){
var texts: [String] = []
OTPTxtFields.forEach { texts.append($0.text!)}
sentOTPOption(currentText: texts.reduce("", +))

}

func sentOTPOption(currentText: String) {
print("AllTextfieldValue == \(currentText)")
}

How to make text typed in TextField undeletable?

The idea is the create UITextField class and use UIViewRepresentable to bind with SwiftUI view. By this, you can use all delegate methods and detect backspace. Also, using this you can prevent from cut and delete from tap action.

UndeletableTextField custom class

class UndeletableTextField: UITextField {

// This for prevent to cut and delete
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.cut(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}

UIViewRepresentable view

struct UndeletableTextFieldUI: UIViewRepresentable {

@Binding var text: String
var placeholder: String

func makeUIView(context: Context) -> UndeletableTextField {
let textField = UndeletableTextField(frame: .zero)
textField.delegate = context.coordinator
textField.placeholder = placeholder
return textField
}

func updateUIView(_ uiView: UndeletableTextField, context: Context) {
uiView.text = text
}

func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}

class Coordinator: NSObject, UITextFieldDelegate {
var parent: UndeletableTextFieldUI

init(parent: UndeletableTextFieldUI) {
self.parent = parent
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Here we detect backspace and ignore it.
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
return false
}
}
return true
}
}
}

ContentView

struct ContentView: View {
@State private var text: String = ""
var body: some View {
UndeletableTextFieldUI(text: $text, placeholder: "Type here")
}
}

What is the use of '\b' (backspace)

Backspace is a control character that moves the cursor one character back in the console but doesn't delete it.

What's the reason for the backspace character, and how might it be used?

It was used historically in the ASCII world to print accented characters.

For example à could be produced using the three character sequence a Backspace ` (or, using the characters' hex values, 0x61 0x08 0x60).

See more on backspace here

Backspace key vs Backspace character

A lot of people confuse the two. Backspace key on keyboard has almost the universal function to delete the previous character (= move cursor back and delete that character). The backspace character '\b' however only moves the cursor one position back in the console window and doesn't delete it.



Related Topics



Leave a reply



Submit