Search code examples
htmldomvb6

Code to make a DHTMLEd control replace straight quotes with curly quotes


I've got an old, legacy VB6 application that uses the DHTML editing control as an HTML editor. The Microsoft DHTML editing control, a.k.a. DHTMLEd, is probably nothing more than an IE control using IE's own native editing capability internally.

I'd like to modify the app to implement smart quotes like Word. Specifically, " is replaced with or and ' is replaced with or as appropriate as it is typed; and if the user presses Ctrl+Z immediately after the replacement, it goes back to being a straight quote.

Does anyone have code that does that?

If you don't have code for DHTML/VB6, but do have JavaScript code that works in a browser with contentEditable regions, I could use that, too


Solution

  • Here's the VB6 version:

    Private Sub DHTMLEdit1_onkeypress()
        Dim e As Object
        Set e = DHTMLEdit1.DOM.parentWindow.event
        'Perform smart-quote replacement'
        Select Case e.keyCode
        Case 34: 'Double-Quote'
            e.keyCode = 0
            If IsAtWordEnd Then
                InsertDoubleUndo ChrW$(8221), ChrW$(34)
            Else
                InsertDoubleUndo ChrW$(8220), ChrW$(34)
            End If
        Case 39: 'Single-Quote'
            e.keyCode = 0
            If IsAtWordEnd Then
                InsertDoubleUndo ChrW$(8217), ChrW$(39)
            Else
                InsertDoubleUndo ChrW$(8216), ChrW$(39)
            End If
        End Select
    End Sub
    
    Private Function IsLetter(ByVal character As String) As Boolean
        IsLetter = UCase$(character) <> LCase$(character)
    End Function
    
    Private Sub InsertDoubleUndo(VisibleText As String, HiddenText As String)
        Dim selection As Object
        Set selection = DHTMLEdit1.DOM.selection.createRange()
        selection.Text = HiddenText
        selection.moveStart "character", -Len(HiddenText)
        selection.Text = VisibleText
    End Sub
    
    Private Function IsAtWordEnd() As Boolean
    
        Dim ch As String
        ch = PreviousChar
        IsAtWordEnd = (ch <> " ") And (ch <> "")
    
    End Function
    
    Private Function PreviousChar() As String
    
        Dim selection As Object
        Set selection = m_dom.selection.createRange()
        selection.moveStart "character", -1
        PreviousChar = selection.Text
    
    End Function
    

    Note: this solution inserts an additional level in the undo chain. For example, typing "This is a test" gives a chain of “This is a test” -> “This is a test" -> “This is a test -> “ -> " (extra level in bold). To remove this extra level you'd have to implement some sort of PostMessage+subclassing solution that doesn't involve cancelling the native keypress

    edit: Don't forget to include the DHTML Editing Control redistributable if you are targeting Windows Vista.