Announcement

Collapse
No announcement yet.

RichEdit - Highlight While Speaking - Multiline Fail

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • RichEdit - Highlight While Speaking - Multiline Fail

    In another thread we discussed highlighting wordwrapped text in a RichEdit control as it is spoken. In the example I posted, the text was a one liner ... something like this:

    Code:
    wTextZ =  "Now is the time to play tennis!"
    But I was playing with it some more today, making the text 2 lines, something like this ...

    Code:
             wTextZ =  "Now is the time" + $CrLf + $CrLf
             wTextZ += "to play tennis!"
    In the code (below) the single line text reads and highlights correctly. However, the two line version ($CRLF delmiiter) reads just fine but does not highlight correctly. The highlighting appears to work until it reaches a word beyond the delimiter, at which point the highlighting is not longer aligned to the word being spoken. The highlighting appears to be offset 1 char for each $CRLF delimiter.

    The returned nstart/nlength values appear to be correct, taking into account the delimiters. The the RichEdit control does not portion of the text that corresponds to the nstart/nlength values. It's as though the %EM_SelSel function recognizes the delimiter as only a single character, thus causing the 1 character offset.

    Anyone noticed this before?

    Code:
    'Compilable Example:
    #Compiler PBWin 10
    #Compile Exe
    #Dim All
    
    %Unicode=1
    #Include "win32api.inc"
    #Include "sapi.inc"
    
    #Resource Manifest, 1, "xptheme.xml"
    
    Enum Equates Singular
       IDC_Speak     = 500
       IDC_RichEdit
       IDC_Stop
       IDC_Reset
    
       IsStopped = 0
       IsSpeaking
       IsPaused
    End Enum
    
    %Msg_SAPI_Event = %WM_User + 1
    
    Global hDlg,hRichEdit,hFont,hWin As Dword
    Global Speaking As Long, wTextZ, wEmptyZ As WStringZ*1000, pSp As ISpVoice
    
    Function PBMain() As Long
       Txt.Window "Debug", 1000,200,30,40 To hWin
       Dialog Default Font "Tahoma", 14, 1
       Dialog New Pixels, 0, "SAPI Test",100,200,800,325, %WS_OverlappedWindow To hDlg
       Control Add Button, hDlg, %IDC_Speak,"Speak", 10,10,100,30
       Control Add Button, hDlg, %IDC_Stop,"Stop", 120,10,100,30
       Control Add Button, hDlg, %IDC_Reset,"Reset", 550,10,100,30
       'add RichEdit
       LoadLibrary("msftedit.dll")
       Control Add "RichEdit50W", hDlg, %IDC_RichEdit, wTextZ,10,50,100,100, _
                %WS_Child Or %WS_ClipSiblings Or %WS_Visible Or %ES_MultiLine Or %WS_VScroll _
                Or %ES_AutoVScroll Or %ES_WantReturn Or %ES_NoHideSel Or %WS_TabStop, %WS_Ex_ClientEdge
       Control Handle hDlg, %IDC_RichEdit To hRichEdit
       'Initialize SAPI
       pSp = NewCom "SAPI.SpVoice"
       pSp.SetInterest(SPFEI(%SPEI_WORD_BOUNDARY) Or SPFEI(%SPEI_END_INPUT_STREAM), SPFEI(%SPEI_WORD_BOUNDARY) Or SPFEI(%SPEI_END_INPUT_STREAM))
       pSp.SetNotifyWindowMessage(hDlg, %MSG_SAPI_EVENT, 0, 0)
       'Set Font
       Font New "Tahoma", 72, 1 To hFont
       Control Set Font hDlg, %IDC_RichEdit, hFont
       Control Send hDlg, %IDC_RichEdit, %EM_SetSel, 0,0
       Control Set Focus hDlg, %IDC_RichEdit
       Dialog Show Modal hDlg Call DlgProc
    End Function
    
    CallBack Function DlgProc() As Long
       Local w,h,nStart,nLength As Long, P As CharRange
       Local eventItem As SPEVENT, eventStatus As SPVOICESTATUS
       Select Case Cb.Msg
          Case %WM_InitDialog
             wTextZ =  "Now is the time" + $CrLf             'this does NOT work
             wTextZ += "to play tennis!"
    '         wTextZ =  "Now is the time to play tennis!"     'this works
    
             Control Set Text hDlg, %IDC_Richedit, wTextZ
          Case %WM_Size
             Dialog Get Client hDlg To w,h
             Control Set Size hDlg, %IDC_RichEdit, w-20,h-60
          Case %WM_Command
             Select Case Cb.Ctl
                Case %IDC_Speak
                   Select Case Speaking
                      Case %IsStopped  : Speaking = %IsSpeaking : pSp.Speak(wTextZ, %SPF_Async, ByVal %Null)  'stops speaking by send empty string
                      Case %IsSpeaking : Speaking = %IsPaused   : psp.Pause
                      Case %IsPaused   : Speaking = %IsSpeaking : psp.Resume
                   End Select
                   If Speaking = %IsStopped  Then Control Set Text hDlg, %IDC_Speak, "Speak"
                   If Speaking = %IsSpeaking Then Control Set Text hDlg, %IDC_Speak, "Pause"
                   If Speaking = %IsPaused   Then Control Set Text hDlg, %IDC_Speak, "Resume"
    
                Case %IDC_Stop
                   Speaking = %IsStopped
                   Control Set Text hDlg, %IDC_Speak, "Speak"
                   pSp.Speak(wEmptyZ, %SVSFPurgeBeforeSpeak, ByVal %NULL)  'stops speaking by sending empty string
                   Control ReDraw hDlg, %IDC_RichEdit
                Case %IDC_Reset
                   Speaking = %IsStopped
                   pSp.Speak(wEmptyZ, %SVSFPurgeBeforeSpeak, ByVal %NULL)  'stops speaking by sending empty string
                   Control Set Text hDlg, %IDC_Speak, "Speak"
                   Control Set Text hDlg, %IDC_RichEdit, wTextZ
                   Control Send hDlg, %IDC_RichEdit, %EM_SetSel,0,0        'did not use EXSetSel because content is small
             End Select
          Case %Msg_SAPI_Event
             Do
                If pSp.GetEvents(1, eventItem, ByVal %NULL) <> %S_Ok Then Exit Do
                Select Case eventItem.eEventID
                   Case %SPEI_WORD_BOUNDARY
                      pSp.GetStatus(eventStatus, ByVal %NULL)
                      nStart = eventStatus.ulInputWordPos
                      nLength = eventStatus.ulInputWordLen
                      Control Send hDlg, %IDC_RichEdit, %EM_SetSel, nStart, nStart+nLength  'select
                      Txt.Print Mid$(wTextZ,nStart+1,nLength) + "  nStart: " + Str$(nStart) + "   nLength: " + Str$(nLength)
                   Case %SPEI_END_INPUT_STREAM
                      Speaking = %IsStopped
                      Control Set Text hDlg, %IDC_Speak, "Speak"
                      Control Set Focus hDlg, %IDC_RichEdit
                End Select
             Loop
       End Select
    End Function

  • #2
    As a test, I replaced the $CRLF with $LF and the speak/highlighting seems to work correctly - the word spoken is also highlighted.

    I just wasn't expecting the $CRLF to create a problem!

    Comment


    • #3
      > I just wasn't expecting the $CRLF to create a problem!

      Nobody Expects The Spanish Inquisition..
      If one grab text from RichEdit, it contains $CRLF, so the problem should be in how MS SAPI returns word positions. Replace $CRLF with $CR.. before letting it do its thing.
      I did a spellchecker for RichEdit once and don't remember $CRLF to be a problem.

      Comment


      • #4
        Hm, I may have been wrong there - found this note in my old spell checker code: "Later versions of RichEdit use single character line feed with EM_SETSEL and EM_EXSETSEL, so must REPLACE $CRLF WITH $LF in grabbed text else selection will become out of sync with actual text."

        Comment


        • #5
          Originally posted by Borje Hagsten View Post
          Hm, I may have been wrong there - found this note in my old spell checker code: "Later versions of RichEdit use single character line feed with EM_SETSEL and EM_EXSETSEL, so must REPLACE $CRLF WITH $LF in grabbed text else selection will become out of sync with actual text."
          Should be $CR, not $LF ?

          https://docs.microsoft.com/en-us/win...-edit-controls

          Microsoft Rich Edit 1.0 used CR/LF character combinations for paragraph markers. Microsoft Rich Edit 2.0 used only a carriage return character ('\r'). Microsoft Rich Edit 3.0 uses only a carriage return character but can emulate Microsoft Rich Edit 1.0 in this regard.

          Note: It doesn't say anything about Rich Edit 4.1 nor how to emulate 1.0 behaviour in 3.0.

          Comment


          • #6
            Yeah, you are right Stuart, $CR. For me it didn't matter, because I only needed a one-character linefeed to keep selection of misspelled words in sync with used textbuffer.

            Comment


            • #7
              In my test (Post #2) I use LF not CR. That worked, but on the link Stuart posted MSDN says CR is the character to use, as Borje also says. The link may not have full information? Safer to go with what they say, I suppose.

              ... added ... when I put in a $CRLF, I get back a $CRLF. Don't know if that's PowerBASIC or the RichEdit making the translations.

              Comment


              • #8
                Yes, one of many "features" in RichEdit. Not a PowerBASIC issue - a SetSel issue. Have tried borth streaming out text and plain Get Text with same result - $CRLF - in all versions, which is why I had to replace all CRLF with single character line feeds to keep seletion in sync with grabbed text.

                Comment

                Working...
                X