Disabling iOS Smart Punctuation

The iOS ‘Smart Punctuation’ feature, which is enabled by default, substitutes single and double-quote characters with their (UTF-8) ‘left’ and ‘right’ paired versions. I have to tell my users to disable this setting globally, but it would be better to do it just for my app.

Apparently this can be achieved with an NSTextView setting: textView.automaticQuoteSubstitutionEnabled = NO but I have no idea how I would do this in an SDL2 app. Can anybody help?

Does nobody know? Mine can’t be the only SDL2 app which doesn’t want keyboard input ‘fiddled with’ by the iOS Smart Punctuation feature.

I am not a 100% sure here, but I think you are talking about when someone does the StartText input (I don’t remember the name of the function for this) , that will show the keyboard on the iOS device. Now, in Android this is done with a hidden text input field that gets selected (and perhaps resized too) and then goes out of focus after the keyboard is dismissed.

I imagine the iOS or macOS stuff works the same. So this would be something in a Objective-C file of SDL2.

I don’t know the backend iOS uses for this, but a possible candidate maybe it’s this one

Anyway, take a look at the ObjectiveC files and see if you can find where there is a text box used for input.

As far as I know the Smart Punctuation feature works the same whether it is the on-screen keyboard or a physical keyboard (e.g. Bluetooth). There’s no reason I can think of why it would apply only to the on-screen keyboard.

I don’t know the backend iOS uses for this, but a possible candidate maybe it’s this one

That refers to a textField object not the textView object required to disable Smart Punctuation. A Google search finds this comment at Wikipedia: “Each NSTextField uses a shared instance of a NSTextView”.

There is what seems to be some relevant code at StackOverflow but I’m not sure how to apply it:

class MyTextFieldCell: NSTextFieldCell {

    override func setUpFieldEditorAttributes(_ textObj: NSText) -> NSText {
        super.setUpFieldEditorAttributes(textObj)
        if let textView = textObj as? NSTextView {
            textView.isAutomaticQuoteSubstitutionEnabled = false
        }
        return textObj
    }

}

So that code sample is for macOS, not iOS. NSTextView/Field = macOS, UITextView/Field = iOS

For iOS, you’ll need to somehow get ahold of the UITextField (which gets the text input) and then do

textField.smartQuotesType = UITextSmartQuotesNo;
textField.smartDashesType = UITextSmartDashesNo;

(put this in an Objective-C file somewhere)

One gross way to do it would be to get the UIWindow from SDL then walk its children, checking to see if any are a UITextField, and setting these properties for each one. Been a while since I’ve done any serious Objective-C or UIKit stuff, but something like

// ***UNTESTED***

#import <UIKit/UIKit.h>
#import <SDL2/SDL_video.h>
#import <SDL2/SDL_syswm.h>

int disableSmartQuotes(SDL_Window *sdlWindow)
{
	SDL_SysWMInfo info;
	SDL_VERSION(&info.version);    // required for following function call
	SDL_bool success = SDL_GetWindowWMInfo(sdlWindow, &info);
	if(success && info.subsystem == SDL_SYSWM_UIKIT) {
		// Need to get the UIWindow, then the UIView
    	UIWindow *iosWindow = info.uikit.window;
		UIViewController *viewController = iosWindow.rootViewController;
		UIView *rootView = viewController.view;

		// Check each subview to see if it's a UITextField (or subclass)
		// and if YES then set the appropriate properties
		for(UIView *view in rootView.subviews) {
			if([view isKindOfClass:[UITextField class]]) {
				UITextField *textField = (UITextField *)view;
				textField.smartQuotesType = UITextSmartQuotesNo;
				textField.smartDashesType = UITextSmartDashesNo;
			}
		}
	} else {
		return -1;
	}

	return 0;
}

You could put that in an Objective-C file somewhere (disableSmartQuotes.m) with appropriate header. Since it’s a C function with Objective-C code inside, you can call it from C code.

edit: An even grosser way would be to modify SDL’s keyboard init code to set those properties. Perhaps someone could create a hint to tell SDL to disable the smart quotes.

That would undoubtedly be the best way, and I’m sure I wouldn’t be the only one to benefit, but at this stage I guess they’d only want to put it in SDL3 which wouldn’t help me.

I don’t like to modify the SDL2 source but I already do that (for other reasons) in my Android build so I suppose it’s no worse to do it in iOS. I have in the past tried to automate this kind of thing in my makefile using sed so that could be something to pursue.

But you’ve certainly got much closer to a solution than I managed, so many thanks.