How to prevent smart quotes from being entered into a TextArea

Somewhere along the way, I believe with Xojo 2014r3, the TextArea object gained the ability to get the automatic “smart quotes” feature from OS X.

As it turns out, my app needs to allow the user to type into a TextArea and the resulting text must not have the regular quotes auto-magically replaced with smart quotes.

I have tried turning off the “automatically check spelling” and “styled” properties of the TextArea, but neither of these disable the automatic substitution of smart quotes. For whatever reason, the TextField object doesn’t get smart quotes. Only TextArea objects.

Does anyone have any ideas how to keep OS X from replacing regular quotes with smart quotes in certain TextAreas?

in the KEYPRESS check if “KEY” is a smart quote character and return TRUE if it is
if they are inserted “automagically” then you will have to use REPLACEALL

in open event with MBS Plugin:

Sub Open() dim n as NSTextViewMBS = me.NSTextViewMBS n.AutomaticQuoteSubstitutionEnabled = false End Sub

That function is included in MacOSLib too.

If the TextArea is not styled, you can implement this in the TextChange event too. You just have to restore the SelStart and SelLen when you’re done.

I recommend this over KeyDown because it will catch paste and drag-and-drop text too.

Since the script manager replaces automagically regular quotes, you want to monitor when special quotes appear and replace them in the Text property :

Sub TextChange() // double quotes me.text = replaceall(me.text,&u201C,chr(34)) me.text = replaceall(me.text,&u201D,chr(34)) // single quotes me.text = replaceall(me.text,&u2018,"'") me.text = replaceall(me.text,&u2019,"'") // lower right quotes me.text = replaceall(me.text,&u201A,"'") // ‚ me.text = replaceall(me.text,&u201E,chr(34)) // „ End Sub

make a Method

  Sub setAutomaticQuoteSubstitutionEnabled(t as TextArea, value as Boolean)
  #if TargetCocoa then
    Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
    
    dim myTextArea as ptr
    declare function documentView lib "Cocoa" selector "documentView" _
    (obj_id as Integer) as Ptr
    
    myTextArea = documentView(t.Handle)
    
    Declare Sub setAutomaticQuoteSubstitutionEnabled Lib "Cocoa" Selector "setAutomaticQuoteSubstitutionEnabled:" _
    (Id as ptr, value as Boolean)
    
    setAutomaticQuoteSubstitutionEnabled (myTextArea, value)
  #endif
End Sub

In Open Event

setAutomaticQuoteSubstitutionEnabled TextArea1, false

or a Button or CheckBox to toggle AutomaticQuoteSubstitution

  #if TargetCocoa then
    Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
    
    dim myTextArea as ptr
    declare function documentView lib "Cocoa" selector "documentView" _
    (obj_id as Integer) as Ptr
    myTextArea = documentView(TextArea1.Handle)
    Declare Sub toggleAutomaticQuoteSubstitution Lib "Cocoa" Selector "toggleAutomaticQuoteSubstitution:"_
     (Id as ptr)
    toggleAutomaticQuoteSubstitution (myTextArea)
  #endif

Smart Quotes are a royal PITA for programmers!

Thanks Axel Schneider, that’s the ticket. I did’t think of disabling it in the native NSTextView. At first I was doing a bunch of ReplaceAll() calls, but clearly, that’s a lot of processing to undo what the OS is doing, and the correct answer is to simply turn off the automatic stuff in the first place.

After playing with it for a while, I discovered that I also needed to turn off not only smart quotes, but also smart dashes and other automatic substitutions (like the user’s own defined substitutions). So, I ended up setting a few more of NSTextView’s flags:

  #if TargetCocoa then
    
    declare function NSClassFromString lib "Cocoa" (aClassName as CFStringRef) as Ptr
    
    declare function documentView lib "Cocoa" selector "documentView" _
        (obj_id as Integer) as Ptr
    
    declare sub setAutomaticQuoteSubstitutionEnabled lib "Cocoa" _
        selector "setAutomaticQuoteSubstitutionEnabled:" _
        (id as ptr, value as Boolean)
    
    declare sub setAutomaticDashSubstitutionEnabled lib "Cocoa" _
        selector "setAutomaticDashSubstitutionEnabled:" _
        (id as ptr, value as Boolean)
    
    declare sub setAutomaticTextReplacementEnabled lib "Cocoa" _
        selector "setAutomaticTextReplacementEnabled:" _
        (id as ptr, value as Boolean)
    
    dim myTextArea as ptr = documentView(self.Handle)
    
    setAutomaticQuoteSubstitutionEnabled(myTextArea, value)
    setAutomaticDashSubstitutionEnabled(myTextArea, value)
    setAutomaticTextReplacementEnabled(myTextArea, value)
    
  #endif

I just ran across this very problem…
and the above declares work well for OSX…

my question… is this an issue for Windows as well, and if so, anyone have a solution similar to the declares…
If necessary, I’ll resort to the REPLACE method but I’d rather not for sake of clarity and speed

I don’t believe it’s an issue on Windows. The smart quotes thing is a Mac text replacement feature. Users can opt to turn it off in System Preferences as well on a system-wide level.

Thanks… I added the declares and it fixed it for macOS perfectly… :slight_smile:

Out of curiosity: what is the problem with smart quotes?

It messes up things like SQL queries and code.

And REST API POST requests!! Grrr. Took me some hours to figure out why my API calls (request content entered into a textarea) were failing. It was friggin smart quotes!! Geez… I fixed it by doing the replaceall thing. Now I’m using the declares.

Thank you!!

It also messes character spacing. One font will have a certain width and another will have 3 times that width.

For those that still need this, Joe Ranieri posted a solution in Feedback back in 2013 that uses a different set of declares (from AppKit instead of Cocoa): <https://xojo.com/issue/25702>. Don’t exactly know what the difference is, but it worked for me.

Some fonts have the same width for a ‘l’ and a ‘m’, some don’t